1.技术难点分析
- 阅读器开发:
- 分页算法、全文搜索算法、引入web字体、主题设计
- 离线存储机制设计:LocalStorage+IndexDB
- 实现各种复杂手势+交互动画,如何兼容手势+鼠标操作
- 利用vuex+mixin实现组件解耦+复用 科大讯飞web在线语音合成API开发
2.项目准备
- 字体图标
- 项目依赖包+项目配置
- 准备web字体
- viewport配置
- rem设置+自适应布局实现思路
- global.scss和reset.scss
- 搭建静态资源服务器Nginx
2.1.字体图标准备
在main.js中引入
$ import "./assets/styles/icon.css"
2.2.安装epubjs依赖包
$ npm install --save epubjs
2.3.准备web字体
然后再在index.html中引入即可,
<link rel="stylesheet" href="<%= BASE_URL %>fonts/daysOne.css">
**在这里需要注意的是,有两种方法引入文本字体,一种是上述所示的方法,另一种是把fonts放到assets中,这时,就不能在index.html中引入,而应该在main 中以import的形式引入
**
2.4.viewport配置
在index.html中
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,minimum-scale=1.0,user-scalable=no">
2.5.rem配置
在App.vue中编写script代码
<script>
export default {
name:"App"
}
document.addEventListener('DOMContentLoaded', () => {
const html = document.querySelector('html')
let fontSize = window.innerWidth / 10
fontSize = fontSize > 50 ? 50 : fontSize
html.style.fontSize = fontSize + 'px'
})
</script>
2.6. global.scss和reset.scss设置
在main中引入
import “./assets/styles/global.scss”
2.7.搭建nginx静态资源服务器
下载方法,及使用方法可参考 博客一文
,主要的命令 就是结束 nginx -s stop;接下来,在D盘的根目录下创建资源文件夹 resource
,然后修改 nginx.conf文件
添加这段代码,自起一个服务端口
server {
listen 8081;
server_name resource;
root D:/resource;
autoindex on;
location / {
add_header Access-Control-Allow-Origin *;
}
add_header Cache-Control "no-cache,must-revalidate";
}
当出现这个,说明成功了
3.阅读器–标题菜单、字号字体及主题设置功能开发
3.1.需求分析图
看看需求分析图
主要技术难点
- epubjs
- vuex+mixin
- vue-i18n
- 动态切换主题+书签手势操作
3.2.阅读器解析和渲染
把epub文件夹(放有所有epub电子书的文件夹)放到resource当中
由于访问资源每一本书的url是 http://localhost:8080/#/ebook/education/202yalishanda
这种方式,可见要用动态路由的方式来访问资源
什么是动态路由?听我说来
这种就是动态路由
,然后我们在浏览器上输入
http://localhost:8080/#/ebook/asasd
在EBook Reader中
<template>
<div class="ebook-reader">
{
{$route.params.fileName}}
</div>
</template>
接收到了参数
这就是动态路由
到了这这里想要获取nginx上的电子书时出现了跨域问题,暂时解决不了,先用 本地资源
3.3.翻页功能的实现
当屏幕向左划时,向上翻页,反之翻下一页。
//监听滑动翻页事件
this.rendition.on("touchstart",event=>{
this.touchStartX = event.changedTouches[0].clientX;
this.touchStartTime = event.timeStamp;
});
this.rendition.on("touchend",event=>{
const offsetX = event.changedTouches[0].clientX-this.touchStartX;
const time = event.timeStamp - this.touchStartTime;
if(time<500 && offsetX>40){
this.prevPage();
}else if (time<500 && offsetX<-40) {
this.nextPage();
}else{
this.toggleTitleAndMenu()
}
})
prevPage(){
if (this.rendition){
this.rendition.prev();
// this.$store.dispatch("setMenuVisible",false)
this.setMenuVisible(false);
}
},
nextPage(){
if (this.rendition){
this.rendition.next();
// this.$store.dispatch("setMenuVisible",false)
this.setMenuVisible(false);
}
},
在这里,值得注意的一点,需要修改epubjs的版本,修改为 “epubjs”: “0.3.71”,因为0.38以上的都不支持滑动
3.4.标题栏和菜单栏实现
先创建标题栏和菜单栏组件
//EbookTitle
<template>
<transition name="slide-down">
<div class="title-wrapper" v-show="menuVisible">
<div class="left">
<span class="icon-back"></span>
</div>
<div class="right">
<div class="icon-wrapper">
<span class="icon-book"></span>
</div>
<div class="icon-wrapper">
<span class="icon-cart"></span>
</div>
<div class="icon-wrapper">
<span class="icon-more"></span>
</div>
</div>
</div>
</transition>
</template>
<script>
// import {mapGetters} from "vuex"
import {
ebookMixin } from "./../../utils/mixin"
export default {
name: "EbookTitle",
mixins:[ebookMixin],
// computed:{
// ...mapGetters(["menuVisible"])
// }
}
</script>
<style lang='scss' scoped>
@import './../../assets/styles/global';
.title-wrapper {
position: absolute;
top: 0;
left: 0;
z-index: 101;
display: flex;
width: 100%;
height: px2rem(48);
background: white;
box-shadow: 0 px2rem(8) px2rem(8) rgba(0, 0, 0, .15);
font-size: px2rem(20);
.left {
flex: 0 0 px2rem(60);
@include center;
}
.right {
flex: 1;
display: flex;
justify-content: flex-end;
.icon-wrapper {
flex: 0 0 px2rem(40);
@include center;
.icon-cart {
font-size: px2rem(22);
}
}
}
}
</style>
//EbookMenu
<template>
<div>
<transition name="slide-up">
<div class="menu-wrapper" :class="{
'hide-box-shadow':!menuVisible}" v-show="menuVisible">
<div class="icon-wrapper">
<span class="icon-menu icon" @click="showSetting(3)"></span>
</div>
<div class="icon-wrapper">
<span class="icon-progress icon" @click="showSetting(2)"></span>
</div>
<div class="icon-wrapper">
<span class="icon-bright icon" @click="showSetting(1)"></span>
</div>
<div class="icon-wrapper">
<span class="icon-a icon" @click="showSetting(0)">A</span>
</div>
</div>
</transition>
</div>
</template>
<script>
// import {mapGetters} from "vuex";
import {
ebookMixin } from "../../utils/mixin.js"
export default {
name: "EbookMenu",
mixins:[ebookMixin],
// computed:{
// ...mapGetters(["menuVisible"])
// },
methods:{
showSetting(){
}
}
}
</script>
<style lang='scss' scoped>
@import './../../assets/styles/global';
.menu-wrapper {
position: absolute;
bottom: 0;
left: 0;
z-index: 102;
display: flex;
width: 100%;
height: px2rem(48);
background: white;
box-shadow: 0 px2rem(-8) px2rem(8) rgba(0, 0, 0, .15);
font-size: px2rem(20);
&.hide-box-shadow {