在开发web阅读器过程中使用epub.js时遇到了不少问题,现在分享下解决思路
首先前端使用了layui,本文不介绍关于这个框架的用途,所以遇到layui的代码请自行查阅layui官方文档:layui
先贴上我的代码吧
openBook: function () {
let that = this, index;
layui.use('layer', function () {
that.layer = layui.layer;
index = that.layer.msg('加载中...', {
icon: 16,
shade: 0.3
});
});
book.open(url);
rendition = book.renderTo("text", {
width: "100%",
height: "100%",
script: "/script/inject"
});
console.log(book);
console.log(rendition);
rendition.display(progress ? progress : 0);
book.ready.then(() => {
navigation = book.navigation;
console.log(navigation);
$.each(navigation.toc, function (index, item) {
$("#catalog").append(`
<a href="javascript:" id="`+ item['id'] +`">
<div class="sections">
`+ item['label'] +`
</div>
</a>
`);
$("#" + item['id']).on("click", function () {
that.selectSection(item['id']);
});
});
// return book.locations.generate();
}).then(result => {
locations = book.locations;
console.log(locations);
spine = locations.spine;
console.log(spine);
$("#total").text(spine.spineItems.length);
bookAvailable = true;
// rendition.on("displayed", function (section) {
// console.log(section);
// pageInput.val(spine.spineByHref[section.href] + 1);
// });
rendition.on("locationChanged", function (info) {
console.log(info);
pageInput.val(info.index + 1);
currentLocation = info.start;
});
that.layer.close(index);
});
}
以上并不是完整的代码,仅代表epub打开书本部分的解决思路
若有必要,我会在后面的文章中贴出完整的代码
epub中有几个重要的对象:book,rendition,navigation,locations,spine,theme
在我的代码中,正确打开书本后控制台会输出以上几个对象,Book是整本书的对象,对于该对象我用到的地方不多,只有
book.open(url);
book.renderTo("text", { width: "100%", height: "100%", script: "/script/inject" });
locations = book.locations;
这三个部分,首先第一个打开对应资源我就不介绍了,需要说明的是renderTo方法和locations属性
renderTo是将书本渲染到指定DOM元素上,由于官方文档介绍并不全面,对于一些不清楚作用的参数我并没有使用,第二个参数传入的对象中,width表示渲染的宽度,height表示高度
重点需要说明的是script属性,这个属性的作用是在渲染出的内联框架的文档中插入<script>标签,并赋予src值为属性的值,由于epub是通过内联框架来显示电子书的,并且书本是异步生成的,我在使用的过程中一直没法获取框架中的DOM对象,所以想要通过点击电子书使阅读页面上的控制栏实现伸缩的效果一直无法实现,直到后来我在文档中找到了这个属性
由于这个属性是直接将src赋予对应的值,所以使用时可以使用静态资源或者直接在后台生成对应的js脚本文本
@RequestMapping("/script/inject")
public void renderScriptInject(HttpServletResponse response) throws IOException {
PrintWriter out = response.getWriter();
InputStream in = new ClassPathResource("static/lib/jquery.js").getInputStream();
byte []jquery = new byte[in.available()];
in.read(jquery);
out.print(new String(jquery));
in = new ClassPathResource("static/js/viewer.js").getInputStream();
byte []viewer = new byte[in.available()];
in.read(viewer);
in.close();
out.print("\r\n");
String script = new String(viewer);
out.print(script);
out.flush();
out.close();
}
这个是我后台注入脚本的代码,由于生成的iframe是一个独立的文档,父窗口引入的jquery在子窗口中不生效,需要另外插入
book.locations是获取locations对象的方式,locations用于标识epub中的各个定位符,获取完整的值需要使用该对象的generate()方法,此方法返回的是整本书所有元素的定位符,值得一提的是这个方法虽然的是异步的,但是耗时很长,我用自己的电脑生成一本大概10M的epub的定位符需要花费数分钟甚至十来分钟的时间,所以我来写完之后发现这个方法并不怎么需要用到,就注释掉了