epub.html 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <meta name="viewport"
  6. content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
  7. <title>EPUB</title>
  8. <script src="https://cdn.bootcdn.net/ajax/libs/jszip/3.1.5/jszip.min.js"></script>
  9. <script src="https://fastly.jsdelivr.net/npm/epubjs@0.3.88/dist/epub.min.js"></script>
  10. <script>
  11. document.addEventListener('DOMContentLoaded', () => {
  12. const html = document.querySelector('html')
  13. let fontSize = window.innerWidth / 10
  14. fontSize = fontSize > 50 ? 50 : fontSize
  15. html.style.fontSize = fontSize + 'px'
  16. })
  17. </script>
  18. <style>
  19. * {
  20. padding: 0;
  21. margin: 0;
  22. }
  23. .mask {
  24. position: absolute;
  25. display: flex;
  26. left: 0;
  27. width: 100%;
  28. height: 100%;
  29. flex-direction: column;
  30. }
  31. .meun {
  32. display: flex;
  33. height: 1rem;
  34. align-items: center;
  35. }
  36. #toc {
  37. flex: 1;
  38. z-index: 100;
  39. font-size: .3rem;
  40. padding-left: .4rem;
  41. color: #333;
  42. }
  43. #page {
  44. z-index: 100;
  45. font-size: .3rem;
  46. color: #333;
  47. padding-right: 0.4rem;
  48. text-align: right;
  49. flex: 0 0 .5rem;
  50. }
  51. #load {
  52. z-index: 100;
  53. font-size: .3rem;
  54. color: #333;
  55. padding-right: 0.4rem;
  56. text-align: right;
  57. flex: 0 0 .5rem;
  58. }
  59. #toc-content {
  60. position: absolute;
  61. display: flex;
  62. top: 0;
  63. right: 0;
  64. z-index: 102;
  65. min-width: auto;
  66. max-width: 80%;
  67. height: 100%;
  68. background: white;
  69. flex-direction: column
  70. }
  71. #toc-mask {
  72. position: absolute;
  73. top: 0;
  74. left: 0;
  75. z-index: 101;
  76. width: 100%;
  77. height: 100%;
  78. background: rgba(51, 51, 51, .8);
  79. }
  80. .intro {
  81. width: 100%;
  82. height: 2.4rem;
  83. padding: .2rem .4rem;
  84. box-sizing: border-box;
  85. height: 3rem;
  86. display: flex;
  87. border-bottom: .1rem solid #f4f4f4;
  88. }
  89. .txt {
  90. display: flex;
  91. flex: 1;
  92. align-items: center;
  93. padding: 0 .2rem;
  94. font-size: .3rem;
  95. }
  96. #content {
  97. overflow-y: auto;
  98. }
  99. .item {
  100. padding: .2rem .4rem;
  101. border-bottom: .07rem solid #f4f4f4;
  102. font-size: .4rem;
  103. color: #333;
  104. }
  105. #open {
  106. display: flex;
  107. flex: 1;
  108. z-index: 100;
  109. font-size: .4rem;
  110. color: #333;
  111. align-items: flex-end;
  112. justify-content: center;
  113. }
  114. #open span {
  115. padding: .3rem .3rem;
  116. border: .05rem solid #333;
  117. border-radius: .2rem;
  118. }
  119. .read {
  120. display: flex;
  121. flex: 1 1 auto;
  122. }
  123. #prev {
  124. flex: 0 0 2rem;
  125. z-index: 100;
  126. }
  127. #viewer {
  128. flex: 1;
  129. }
  130. #next {
  131. flex: 0 0 2rem;
  132. z-index: 100;
  133. }
  134. .save {
  135. display: flex;
  136. }
  137. .box {
  138. padding: .2rem .2rem;
  139. justify-content: center;
  140. border-bottom: .1rem solid #f4f4f4;
  141. }
  142. .jump {
  143. display: flex;
  144. height: 1rem;
  145. border-bottom: .1rem solid #f4f4f4;
  146. }
  147. .jump input {
  148. flex: 1;
  149. padding: .1rem .1rem;
  150. margin: .2rem .2rem .2rem .4rem;
  151. outline: none;
  152. font-size: .3rem;
  153. }
  154. .jump span {
  155. flex: 0 0 1rem;
  156. }
  157. </style>
  158. </head>
  159. <body>
  160. <div id="ebook">
  161. <div class="mask">
  162. <div id="open">
  163. <span
  164. onclick="document.getElementById('input').click();document.getElementById('open').style.display = 'none'">选择本地书籍</span>
  165. <input type="file" id="input" style="display: none;">
  166. </div>
  167. <div class="read">
  168. <div id="prev" onclick="rendition.prev()"></div>
  169. <div id="viewer"></div>
  170. <div id="next" onclick="rendition.next()"></div>
  171. </div>
  172. <div class="meun">
  173. <div id="toc" onclick="showhide()"></div>
  174. <div id="page"></div>
  175. <div id="load"></div>
  176. </div>
  177. <div id="toc-mask" style="display: none;" onclick="showhide()"></div>
  178. <div id="toc-content" style="display: none;">
  179. <div class="intro">
  180. <img id="cover">
  181. <div style="display: flex;flex: 1;flex-direction: column;overflow-y: auto;">
  182. <div id="title" class="txt"></div>
  183. <div id="author" class="txt"></div>
  184. <div id="publisher" class="txt"></div>
  185. <div id="pubdate" class="txt"></div>
  186. </div>
  187. </div>
  188. <div class="save">
  189. <div class="txt box" onclick="save()">存档</div>
  190. <div class="txt box" onclick="get()">读档</div>
  191. <div class="txt box" onclick="del()">删档</div>
  192. </div>
  193. <div class="jump">
  194. <input id="jump" type="number" placeholder="0-1之间的数字,如0.25"
  195. oninput="if(value>1)value=1;if(value<0)value=0">
  196. <span class="txt" onclick="jump()">跳转</span>
  197. </div>
  198. <div id="content"></div>
  199. </div>
  200. </div>
  201. </div>
  202. <script>
  203. let url = location.search.substring(3);
  204. if (url !== "") {
  205. var book = ePub(url);
  206. document.getElementById("open").style.display = "none"
  207. } else {
  208. var book = ePub();
  209. var inputElement = document.getElementById("input");
  210. inputElement.addEventListener('change', function (e) {
  211. var file = e.target.files[0];
  212. if (window.FileReader) {
  213. var reader = new FileReader();
  214. reader.onload = openBook;
  215. reader.readAsArrayBuffer(file);
  216. }
  217. });
  218. function openBook(e) {
  219. var bookData = e.target.result;
  220. book.open(bookData, "binary");
  221. }
  222. }
  223. //渲染
  224. var rendition = book.renderTo("ebook", {
  225. with: window.innerWidth,
  226. height: window.innerHeight - 20
  227. });
  228. rendition.display();
  229. book.ready
  230. .then(() => {
  231. var local = localStorage.getItem(book.key() + '-locations');
  232. if (local) {
  233. return book.locations.load(local);
  234. } else {
  235. return book.locations.generate();
  236. }
  237. })
  238. .then(locations => {
  239. localStorage.setItem(book.key() + '-locations', book.locations.save());
  240. })
  241. // 目录
  242. book.loaded.navigation.then(toc => {
  243. var read = localStorage.getItem(book.key() + '-read');
  244. if (read) {
  245. rendition.display(read);
  246. }
  247. var $content = document.getElementById("content");
  248. toc.forEach(item => {
  249. var div = document.createElement("div");
  250. div.className = "item";
  251. div.textContent = item.label;
  252. div.addEventListener("click", () => {
  253. rendition.display(item.href);
  254. showhide()
  255. });
  256. $content.appendChild(div)
  257. })
  258. })
  259. //简介
  260. book.loaded.metadata.then(meta => {
  261. var $title = document.getElementById("title");
  262. var $author = document.getElementById("author");
  263. var $cover = document.getElementById("cover");
  264. var $publisher = document.getElementById("publisher");
  265. var $pubdate = document.getElementById("pubdate");
  266. $title.textContent = `书名:${meta.title}`;
  267. $author.textContent = `作者:${meta.creator}`;
  268. $publisher.textContent = `出版社:${meta.publisher}`;
  269. $pubdate.textContent = `时间:${meta.pubdate}`;
  270. if (book.archive) {
  271. book.archive.createUrl(book.cover)
  272. .then(url => {
  273. $cover.src = url;
  274. })
  275. } else {
  276. $cover.src = book.cover;
  277. }
  278. });
  279. //进度显示
  280. rendition.on('relocated', location => {
  281. var percent = book.locations.percentageFromCfi(location.start.cfi);
  282. var $page = document.getElementById("page");
  283. var $load = document.getElementById("load");
  284. $page.textContent = location.end.displayed.page + '/' + location.end.displayed.total;
  285. $load.textContent = Math.fround(percent * 100).toFixed(1) + '%';
  286. })
  287. //章节名显示
  288. rendition.on("rendered", section => {
  289. var $toc = document.getElementById("toc");
  290. $toc.textContent = "目录";
  291. $toc.textContent = book.navigation.get(section.href).label;
  292. })
  293. function showhide() {
  294. var $toc_content = document.getElementById("toc-content")
  295. var $mask = document.getElementById("toc-mask")
  296. if ($toc_content.style.display == "none") {
  297. $toc_content.style.display = ""
  298. $mask.style.display = ""
  299. } else {
  300. $toc_content.style.display = "none"
  301. $mask.style.display = "none"
  302. }
  303. }
  304. function jump() {
  305. $jump = document.getElementById("jump").value;
  306. rendition.display(book.locations.cfiFromPercentage($jump));
  307. showhide();
  308. document.getElementById("jump").value = "";
  309. }
  310. function save() {
  311. localStorage.setItem(book.key() + '-read', rendition.currentLocation().start.cfi)
  312. showhide()
  313. }
  314. function get() {
  315. rendition.display(localStorage.getItem(book.key() + '-read'));
  316. showhide()
  317. }
  318. function del() {
  319. localStorage.removeItem(book.key() + '-read');
  320. showhide()
  321. }
  322. </script>
  323. </body>
  324. </html>