写在前面的话
实现本阅读器需要进行以下几个步骤:
- 设计书架。(可添加图书,删除图书等)
- 打开并阅读epub图书。(可做高亮、笔记、书签,可显示目录并通过目录跳转)
本篇文章先实现第一项,设计书架,epub的阅读部分将在稍后文章中进行描述。
作者在实现时采用了vue + vue-loader来进行编码,直接使用js实现时原理都是一样的。
先附上效果图:
实现书架主要有以下几点:
- 图书的显示
- 图书的上传。
- 图书的存储。
- 图书的管理。
显示图书
设计对象 files 存储所有图书信息
<div v-for="file in files" class="booklocal">
<div class="readtime">
{{file.readtimedis}}
</div>
<el-card :body-style="{ padding: '0px' }">
![](file.thumbnail)
</el-card>
<div class="filename">
<span>{{file.name}}</span>
</div>
</div>
上传图书
因为在很多时候,我们要通过其他方式来触发文件选择框,所以在此将默认的文件选择器设置为不可见的,然后在其他(图片按钮)地方点击事件中触发文件选择框。
//添加file input并将其设置为不可见
<input type="file" multiple="multiple" class="fileInput" @change="selectedFiles"
ref="inputer" />
.fileInput {
display: none;
}
//设置自定义按钮并在其点击事件中触发文件选择器。
<div class="book-add" v-on:click="addbook">+</div>
.book-add {
width: 60px;
height: 60px;
border-radius: 30px;
background-color: #FB771E;
box-shadow: 5px 5px 10px #272727;
text-align: center;
line-height: 60px;
font-size: 40px;
//设置文字不能选中
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
}
addbook: function(event) {
$('.fileInput').click();
},
//用户选择文件后的触发事件,
selectedFiles: function(event) {
var self = this;
//获取文件
var files = this.$refs.inputer.files;
$.each(files, function(index, file) {//可在此处理上传的文件。
}
}
存储图书
HTML5提供了对象存储技术,可以再IndexedDB数据库中保存Bolb对象,而文件正是一种特殊的Blob对象。
在进行对象存储时,其存储形式为Key---Object(文件),需要对每个文件进行区分,也就是说每个文件需要唯一的Key,在此我们使用MD5来对文件进行区分。
1. 提取文件MD5码
我们使用github上的开源库spark-md5来实现MD5码的提取。代码如下:
selectedFiles: function(event) {
var self = this;
//获取文件
var files = this.$refs.inputer.files;
$.each(files, function(index, file) {
var fileName = file.name;
if (fileName.substr(fileName.indexOf(".")) == '.epub') {
if (file.size / 1024 / 1024 > 200) {
//如果大于20M
self.$notify({
title: '失败',
message: fileName + '大于200M,目前只支持小于200M文件',
type: 'error'
});
} else {
var blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
chunkSize = 2097152, // Read in chunks of 2MB
chunks = Math.ceil(file.size / chunkSize),
currentChunk = 0,
spark = new SparkMD5.ArrayBuffer(),
fileReader = new FileReader();
var md5;
fileReader.onload = function(e) {
spark.append(e.target.result); // Append array buffer
currentChunk++;
if (currentChunk < chunks) {
loadNext();
} else {
md5 = spark.end();//在此处获取MD5码。
}
};
fileReader.onerror = function() {
console.warn('oops, something went wrong.');
};
function loadNext() {
var start = currentChunk * chunkSize,
end = ((start + chunkSize) >= file.size) ? file.size : start + chunkSize;
fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
}
loadNext();
}
} else {
self.$notify({
title: '失败',
message: fileName + '为非epub文件!',
type: 'error'
});
}
});
},
2. 存储图书
使用github上的开源库localForage来对文件进行存储。localForage将对IndexedDB数据库的操作进行了封装,代码如下:
//在vue中引入localForage
import localForage from "localforage";
//初始化localForage
this.store = localForage.createInstance({
name: this.dbName
});
//使用开源库对文件进行存储。(MD5为以上代码获取的MD5值,file为循环中的file)
self.store.setItem(md5, file, function(err) {
});
3. 管理图书
我们先讨论管理图书都需要什么操作,使用什么方式的操作更容易让用户接受,然后再讨论每种操作的实现方式。
- 管理图书所需操作。
- 添加图书
- 导出图书
- 删除图书
- 重命名图书
- 操作方式
使用右键来对其进行操作。如图:
右键菜单使用context.js来实现,具体使用方式请参考使用指南或如下代码:
addRightClick: function() {
var self = this;
context.init({
preventDoubleContext: false
});
context.attach('.booklocal', [{
text: '打开',
action: function(e, selector) {
//添加打开操作
}
}, {
text: '导出',
action: function(e, selector) {
//添加导出操作
}
}, {
text: '重命名',
action: function(e, selector) {
//添加重命名操作
}
}, {
text: '删除',
action: function(e, selector) {
//添加删除操作
}
}]);
},
- 操作的实现方式。
设计文件管理是包含如下属性:
var fileInfo=new Object();
fileInfo.name = file.name; //文件显示的名字
fileInfo.dname = md5; //文件的MD5值
fileInfo.addtime = Date.parse(new Date()); //文件添加日期(如有需要可以添加)
fileInfo.readtime = null; //文件上次阅读时间
fileInfo.readtimedis = "未读过"; //显示给用户的文件上次阅读时间
fileInfo.lastreadurl = null; //文件上次关闭时后的阅读位置,方便下次阅读直接跳转
fileInfo.thumbnail = ""; //文件缩略图
fileInfo.tags=[]; //阅读图书时所添加的标签
fileInfo.notes=[]; //阅读图书时的笔记
导出
//导出
export: function() {
var self = this;
//this.editFile为当前正在操作的文件,可在用户点击右键时获取
this.store.getItem(this.editFile.dname, function(err, file) {
if (file) {
var fileName = self.editFile.name;
if (fileName.substr(fileName.indexOf(".")) == '.epub') {
self.downFile(file, self.editFile.name);
} else {
self.downFile(file, self.editFile.name + ".epub");
}
} else {
}
});
},
//下载
downFile: function(blob, fileName) {
if (window.navigator.msSaveOrOpenBlob) {
navigator.msSaveBlob(blob, fileName);
} else {
var link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = fileName;
link.click();
window.URL.revokeObjectURL(link.href);
}
},
删除
删除就是把图书信息中的本图书删掉即可。
vue的数据绑定机制,会自动删除相应图书。
重命名
重命名跟删除机制一样,只需要修改图书信息中的name即可。
总结:
书架的设计,主要包括图书的显示,图书的上传,图书的存储和图书的管理。
- 使用VUE可以很方便的使界面显示和数据进行同步。
- 图书上传时使用MD5来标记图书,可以方便索引图书。
- 使用localForage可以很方便的对图书进行存储。
- 使用context.js来实现右键菜单,对图书进行管理。