打造web版epub阅读器(书架设计)

/ javascript / 没有评论 / 1490浏览

打造web版epub阅读器(书架设计)

写在前面的话

实现本阅读器需要进行以下几个步骤:

  1. 设计书架。(可添加图书,删除图书等)
  2. 打开并阅读epub图书。(可做高亮、笔记、书签,可显示目录并通过目录跳转)

本篇文章先实现第一项,设计书架,epub的阅读部分将在稍后文章中进行描述。 作者在实现时采用了vue + vue-loader来进行编码,直接使用js实现时原理都是一样的。

先附上效果图:

1

实现书架主要有以下几点:

  1. 图书的显示
  2. 图书的上传。
  3. 图书的存储。
  4. 图书的管理。

显示图书

设计对象 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. 管理图书

我们先讨论管理图书都需要什么操作,使用什么方式的操作更容易让用户接受,然后再讨论每种操作的实现方式。

  1. 管理图书所需操作。
  1. 操作方式 使用右键来对其进行操作。如图: 2 右键菜单使用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) {
            //添加删除操作
        }
    }]);
},
  1. 操作的实现方式。
// 设计文件管理是包含如下属性:
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来实现右键菜单,对图书进行管理。