寫在前面的話
實(shí)現(xiàn)本閱讀器需要進(jìn)行以下幾個(gè)步驟:
- 設(shè)計(jì)書架。(可添加圖書僧家,刪除圖書等)
- 打開并閱讀epub圖書雀摘。(可做高亮、筆記八拱、書簽阵赠,可顯示目錄并通過目錄跳轉(zhuǎn))
本篇文章先實(shí)現(xiàn)第一項(xiàng),設(shè)計(jì)書架乘粒,epub的閱讀部分將在稍后文章中進(jìn)行描述豌注。
作者在實(shí)現(xiàn)時(shí)采用了vue + vue-loader來進(jìn)行編碼伤塌,直接使用js實(shí)現(xiàn)時(shí)原理都是一樣的灯萍。
先附上效果圖:
實(shí)現(xiàn)書架主要有以下幾點(diǎn):
- 圖書的顯示
- 圖書的上傳。
- 圖書的存儲(chǔ)每聪。
- 圖書的管理旦棉。
顯示圖書
設(shè)計(jì)對(duì)象 files 存儲(chǔ)所有圖書信息
<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>
上傳圖書
因?yàn)樵诤芏鄷r(shí)候,我們要通過其他方式來觸發(fā)文件選擇框药薯,所以在此將默認(rèn)的文件選擇器設(shè)置為不可見的绑洛,然后在其他(圖片按鈕)地方點(diǎn)擊事件中觸發(fā)文件選擇框。
//添加file input并將其設(shè)置為不可見
<input type="file" multiple="multiple" class="fileInput" @change="selectedFiles"
ref="inputer" />
.fileInput {
display: none;
}
//設(shè)置自定義按鈕并在其點(diǎn)擊事件中觸發(fā)文件選擇器童本。
<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;
//設(shè)置文字不能選中
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: pointer;
}
addbook: function(event) {
$('.fileInput').click();
},
//用戶選擇文件后的觸發(fā)事件真屯,
selectedFiles: function(event) {
var self = this;
//獲取文件
var files = this.$refs.inputer.files;
$.each(files, function(index, file) {//可在此處理上傳的文件。
}
}
存儲(chǔ)圖書
HTML5提供了對(duì)象存儲(chǔ)技術(shù)穷娱,可以再IndexedDB數(shù)據(jù)庫中保存Bolb對(duì)象绑蔫,而文件正是一種特殊的Blob對(duì)象。
在進(jìn)行對(duì)象存儲(chǔ)時(shí)泵额,其存儲(chǔ)形式為Key---Object(文件)配深,需要對(duì)每個(gè)文件進(jìn)行區(qū)分,也就是說每個(gè)文件需要唯一的Key嫁盲,在此我們使用MD5來對(duì)文件進(jìn)行區(qū)分篓叶。
1. 提取文件MD5碼
我們使用github上的開源庫spark-md5來實(shí)現(xiàn)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. 存儲(chǔ)圖書
使用github上的開源庫localForage來對(duì)文件進(jìn)行存儲(chǔ)。localForage將對(duì)IndexedDB數(shù)據(jù)庫的操作進(jìn)行了封裝俐镐,代碼如下:
//在vue中引入localForage
import localForage from "localforage";
//初始化localForage
this.store = localForage.createInstance({
name: this.dbName
});
//使用開源庫對(duì)文件進(jìn)行存儲(chǔ)母谎。(MD5為以上代碼獲取的MD5值,file為循環(huán)中的file)
self.store.setItem(md5, file, function(err) {
});
3. 管理圖書
我們先討論管理圖書都需要什么操作京革,使用什么方式的操作更容易讓用戶接受奇唤,然后再討論每種操作的實(shí)現(xiàn)方式。
- 管理圖書所需操作匹摇。
- 添加圖書
- 導(dǎo)出圖書
- 刪除圖書
- 重命名圖書
- 操作方式
使用右鍵來對(duì)其進(jìn)行操作咬扇。如圖:
右鍵菜單使用context.js來實(shí)現(xiàn),具體使用方式請(qǐng)參考使用指南或如下代碼:
addRightClick: function() {
var self = this;
context.init({
preventDoubleContext: false
});
context.attach('.booklocal', [{
text: '打開',
action: function(e, selector) {
//添加打開操作
}
}, {
text: '導(dǎo)出',
action: function(e, selector) {
//添加導(dǎo)出操作
}
}, {
text: '重命名',
action: function(e, selector) {
//添加重命名操作
}
}, {
text: '刪除',
action: function(e, selector) {
//添加刪除操作
}
}]);
},
- 操作的實(shí)現(xiàn)方式廊勃。
設(shè)計(jì)文件管理是包含如下屬性:
var fileInfo=new Object();
fileInfo.name = file.name; //文件顯示的名字
fileInfo.dname = md5; //文件的MD5值
fileInfo.addtime = Date.parse(new Date()); //文件添加日期(如有需要可以添加)
fileInfo.readtime = null; //文件上次閱讀時(shí)間
fileInfo.readtimedis = "未讀過"; //顯示給用戶的文件上次閱讀時(shí)間
fileInfo.lastreadurl = null; //文件上次關(guān)閉時(shí)后的閱讀位置懈贺,方便下次閱讀直接跳轉(zhuǎn)
fileInfo.thumbnail = ""; //文件縮略圖
fileInfo.tags=[]; //閱讀圖書時(shí)所添加的標(biāo)簽
fileInfo.notes=[]; //閱讀圖書時(shí)的筆記
導(dǎo)出
//導(dǎo)出
export: function() {
var self = this;
//this.editFile為當(dāng)前正在操作的文件,可在用戶點(diǎn)擊右鍵時(shí)獲取
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的數(shù)據(jù)綁定機(jī)制梭灿,會(huì)自動(dòng)刪除相應(yīng)圖書。
重命名
重命名跟刪除機(jī)制一樣冰悠,只需要修改圖書信息中的name即可堡妒。
總結(jié):
書架的設(shè)計(jì),主要包括圖書的顯示溉卓,圖書的上傳皮迟,圖書的存儲(chǔ)和圖書的管理。
- 使用VUE可以很方便的使界面顯示和數(shù)據(jù)進(jìn)行同步桑寨。
- 圖書上傳時(shí)使用MD5來標(biāo)記圖書伏尼,可以方便索引圖書。
- 使用localForage可以很方便的對(duì)圖書進(jìn)行存儲(chǔ)尉尾。
- 使用context.js來實(shí)現(xiàn)右鍵菜單爆阶,對(duì)圖書進(jìn)行管理。