美文网首页Vue.js前端开发让前端飞
vue-cli@3 + electron开发一款本地小说阅读器(

vue-cli@3 + electron开发一款本地小说阅读器(

作者: 相听不厌 | 来源:发表于2019-07-21 17:02 被阅读33次

vue-cli@3 + electron开发一款本地小说阅读器(一)
vue-cli@3 + electron开发一款本地小说阅读器(二)
vue-cli@3 + electron开发一款本地小说阅读器(三)
vue-cli@3 + electron开发一款本地小说阅读器(四)
vue-cli@3 + electron开发一款本地小说阅读器(五)

一、关于上一篇遗留下来的中文乱码的问题

1、用到iconv-lite

npm i iconv-lite -s -d

2、关于报错_webpack_require()的解决方法

到node_modules中找到iconv-lite文件夹,lib文件夹,打开index.js,最下方有两个require的后一个参数括号去掉,如下:

var nodeVer = typeof process !== 'undefined' && process.versions && process.versions.node;
if (nodeVer) {

    // Load streaming support in Node v0.10+
    var nodeVerArr = nodeVer.split(".").map(Number);
    if (nodeVerArr[0] > 0 || nodeVerArr[1] >= 10) {
        require("./streams");//修改这个
    }

    // Load Node primitive extensions.
    require("./extend-node");//修改这个
}

if ("Ā" != "\u0100") {
    console.error("iconv-lite warning: javascript files use encoding different from utf-8. See https://github.com/ashtuchkin/iconv-lite/wiki/Javascript-source-file-encodings for more info.");
}
3、编写判断编码和转码的js:getTxt.js

判断编码的方法,我这里返回的是需要解码用的格式

 /*
    * 传入txt路径,返回解码的格式
    * */
    judgeCode(path) {
        return new Promise(function (resolve, reject) {
            fs.readFile(path, function (err, buffer) {
                if (err) {
                    reject(err)
                }
                let type;
                if (buffer[0] == 0xff && buffer[1] == 0xfe) {
                    type = 'utf16'
                } else if (buffer[0] == 0xfe && buffer[1] == 0xff) {
                    type = 'utf16'
                } else if (buffer[0] == 0xef && buffer[1] == 0xbb) {
                    type = 'utf8'
                } else {
                    type = 'GBK'
                }
                resolve(type)
            })
        })
    },

然后,根据得到的需要转码的编码利用iconv进行转码并得到数据就可以了

//转换编码
    iconv(type, buf) {
        return iconv.decode(buf, type)
    },
    //获取内容
    getTxt(path) {
        let _that = this;
        return this.judgeCode(path).then(function (type) {
            let buf = fs.readFileSync(path);
            let str = _that.iconv(type, buf)
            return str;
        })
    },
经过测试:txt的四种编码:ansi、unicode、unicodebigendian以及常用的gbk、gb2312都没有问题。

二、关于打包后不能用的说明

我们之前是手动创建的两个json文件,一个用来放book列表,一个用来放标签。打包后文件都会被放到asar中,默认该文件只能读,不能写。当然还有其他一些问题。。。
怎么办?
这里我们需要用到数据库,可能也有其他的解决办法,不过没有时间试验,我们还是用数据库吧。
数据库的选择有两个:NeDB和SQlite,都是嵌入式数据库。NeDB又称为node嵌入式数据库,感兴趣的可以自行了解。我要用的是SQlite,好处嘛也自行百度。
SQlite是用c语言写的,如果直接引用到Electron项目中需要用C语言进行编译后才可以正常使用,关于如何编译,大家可以看苏南大叔的文档,我觉得已经算是最新的文档了。其实现在安装没有这么麻烦了
注意几点:

1、Python 2.7(版本是2.7)
2、手动下载vs_BuildTools安装node.js生成工具,不用下其他的C语言开发环境了,网速慢的话要累死

就是这个
3、npm install windows-build-tools -g 安装这个用管理员安装,如果报错powershell.exe 这种错误就把powershell的路径放到path系统环境变量里去
4、electron的版本改到5.0.6
5、linux系统需要安装g++
大概就这些,然后 npm i sqlite3 -s -d就ok了,会自动编译好,如果有问题,可以找我

三、用数据库代替我们的json文件

control.js

const path = require('path')
const sqlite = require('sqlite3').verbose()
const db = new sqlite.Database(path.join(__static, '../db.db'));

在new的时候他会判断,如果存在就打开,如果不存在就创建数据库。

1、创建两个表,还是在control.js中,创建一个方法

 //初始化,不存在就创建两个表
    init() {
        db.serialize(function () {
            db.run("CREATE TABLE IF NOT EXISTS  BOOKLIST(\n" +
                "   id INT PRIMARY KEY          NOT NULL,\n" +
                "   bookName       TEXT         NOT NULL,\n" +
                "   size           INT          NOT NULL,\n" +
                "   tab            TEXT,\n" +
                "   src            TEXT\n" +
                ");")


            db.run("CREATE TABLE IF NOT EXISTS TABS(\n" +
                "   TABNAME        TEXT\n" +
                ")")

        });
    },

2、插入数据的方法

control.js

create(e) {
        let sql = "INSERT INTO BOOKLIST VALUES('" + e.id + "','" + e.bookName + "', '" + e.size + "', '" + e.tab + "', '" + e.src + "' );";
        // let query = "INSERT INTO BOOKLIST VALUES (7, 'James', 24, 'Houston', 10000.00 );"
        return new Promise(function (resolve, reject) {
                db.run(sql, (err,) => {
                    if (err) reject(err)
                    else {
                        // resolve("插入成功!")
                        store.commit("add")
                    }
                })
            }
        )
    },

3、其他方法:

删除一条book信息的方法、上传txt时判断有没有重复的方法、获取数据库中所有book列表信息的方法、根据标签获取book列表信息的方法、添加标签时判断标签重复的方法、新增标签的方法、获取所有标签的方法、修改标签名的方法、删除标签的方法。大致就这些方法,把这些方法全部封装到control.js文件中,方便我们后面调用。
因为篇幅原因,后续源码放到公众号,欢迎批评指正,我也是萌新!

4、假如数据库的都弄好了,剩下的就是操作数据,更新数据的问题了,主要说点技巧性的

我们引用了数据库后,会发现如果数据库信息发生变化,主要是增加或删除后,如何监听数据变化并及时的渲染到前端上?

我的解决思路是通过vuex来实现,然后当数据库发生改变时,改变vuex的状态,页面层可以用watch来监听vuex的状态,如果发生改变就调用数据库重新获取数据,更新到data。

举例:

1、安装vuex
2、在src下新建一个文件夹store,然后新建一个index.js文件,内容:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const store = new Vuex.Store({
    state:{
        count: 0
    },
    mutations:{
        add(state){
            state.count = state.count + 1
        },
        del(state){
            state.count = state.count - 1
        }
    }

})

export default store

注意区分大小写,否则会报错。
解释:初始化一个count,默认为0,然后有两个方法,一个+1,一个-1。(其实写一个方法就行,只要保证状态发生改变就行了)

3、vue全局注册,到main.js中

import Vue from 'vue'
import App from './App.vue'
import './assets/plugins/element.js'
import store from './store/index'

Vue.config.productionTip = false

new Vue({
    store,
    render: h => h(App),
}).$mount('#app')

4、数据库中调用store方法,到control.js中,引入我们刚才写的index文件

import store from '../../store/index'

我们一开始写的create的方法

//插入一条book信息
    create(e) {
        let sql = "INSERT INTO BOOKLIST VALUES('" + e.id + "','" + e.bookName + "', '" + e.size + "', '" + e.tab + "', '" + e.src + "' );";
        // let query = "INSERT INTO BOOKLIST VALUES (7, 'James', 24, 'Houston', 10000.00 );"
        return new Promise(function (resolve, reject) {
                db.run(sql, (err,) => {
                    if (err) reject(err)
                    else {
                        // resolve("插入成功!")
                        store.commit("add")
                    }
                })
            }
        )
    },

其中:store.commit('add')就是改变状态用的

5、页面中监听,利用watch进行监听,如果改变值了,就执行方法

 watch: {
            '$store.state.count': function () {
                let _that = this
                Control.getAll().then(function (e) {
                    _that.tableData = e;
                })
                Control.getAllTabs().then(function (e) {
                    _that.tabList = e;
                })
            }
        },

5、其他注意的问题

1、不要用alert,用alert后再弹出input输入框会发生input框不能输入的问题。
2、element-ui的Message失效的话,单独引用

import {Message} from 'element-ui';

调用

 Message.error({
                            message: '请选择TXT文件'
                        })

三、效果展示

标签操作 标签增删改 txt增删

结束语

大致的功能实现了,还有一些功能待优化,源码后续会放到微信号里,欢迎大佬指正。
有问题欢迎微信留言,一起交流
微信公众号

相关文章

网友评论

    本文标题:vue-cli@3 + electron开发一款本地小说阅读器(

    本文链接:https://www.haomeiwen.com/subject/flamlctx.html