6.0 KiB
移植经验
- 使用npm下载所有在vue-cli项目所使用的模块,比如element-ui、NProgress之类的。
- 将vue-cli项目中src目录下所有文件复制到electron-vue中对应目录。(不要直接覆盖main.js,因为electron-vue中有一些写法不同了,对于这个文件需要自己仔细移植,比如 Vue.use(require('vue-electron'))就与vue-cli不同)
- 运行npm run dev,解决报错问题。(主要是因为路径失效造成的问题)
this.$router.push()报错then() undefined
这有可能是因为你使用了动态加载路由,也就是在vue-router中使用了vuex,同时夹杂了Electron-vue模板里的东西。在electron-vue模板使用的store/index.js文件中调用了vuex-electron插件,而这些插件貌似会与结构起冲突,把这些东西删除了就好了。
// import { createPersistedState, createSharedMutations } from 'vuex-electron'
// plugins: [
// createPersistedState(),
// createSharedMutations()
// ],
我使用的动态路由是修改自 PanJiaChen/vue-admin-template。该作者也做了个Electron的项目,同样是用Electron-vue模板,所以相当值得参考。
跨域问题
我一开始也很疑惑,为啥electron-vue中为啥没有proxytable。后来发现的确没有必要。如果有,只可能是因为你的需求有问题。
vue-cli项目是将打包好的js、html等文件一起放到服务端中,之后通过浏览器来浏览。服务端和前端文件是放在一起的。所以为了解决前后端分离的问题,才使用跨域转发的方式来解决(开发模式需要跨,而生成模式就不需要)。而Electron开发与生成都需要跨,毕竟前端和服务端不在一起。所以也就不存在跨域问题,也就不需要ProxyTable了。
我的解决方法是这样: 设置一个config.js作为全局设置文件。在里面设置一个变量用于存储本地服务器ip,之后在使用axios编写get与post接口的文件,将服务器ip变量加到接口地址前就可以了。例如
export const requestLogin = params => {return axios.post(`/login`,params).then(res => res.data); };
=>
//在config.js中,base为127.0.0.1:3000
import {base} from '../config';
export const requestLogin = params => {return axios.post(`${base}/login`,params).then(res => res.data); };
如果需要导出web版本,则可以使用process.env.IS_WEB来判断是否为web模式。
静态文件与启动本地服务问题
之前曾想过在electron里直接导入服务端代码来运行服务器,但后来发现不行。github上代码都是通过electron(Node.js)的child_process来启动外部服务器的。
这里我使用pm2来启动,这样就不需要在程序关闭时关闭服务器了。(child_process 老是无法关闭服务器进程,不知道为什么)
let exec = require('child_process').exec;
let server = exec("pm2 start ./bin/www", {cwd: process.cwd()+'/server'});
静态文件可以放再electron目录下的static文件夹中(之后会打包成asar文件),不过因为本人写的app需要定时更新文件,且文件类型较杂,所以使用本地服务端来管理静态文件。
于是对于项目中的需要显示图片或者其他文件链接就需要加入本地服务器ip地址,就像上一节那样。
打包后静态文件失效问题
__dirname是Electron-vue中在webpack中配置的变量,对应开发模式与 产品模式时的electron静态文件目录。但如果你使用了一些webpack中没有设置的文件(比如字体)会出一些问题,请参考这个blog https://blog.csdn.net/aa661020/article/details/79757859
关于自定义协议
本人写的app使用了类似QQ的自定义协议来启动自己写的外部程序并传参,在electron中,为了安全的问题,默认把这个功能屏蔽了。electron中应该可以使用protocol来定义协议来解决问题,不过我找到了另一种方法,那就是直接使用child_process的exec,直接用命令行的方式来启动程序。
直接在渲染进程中(xxx.vue文件)
<script>
const exec = require('child_process').exec;
export default {
methods: {
exec(row){
//s为自定义协议的字符串
let s='xxxxxx';
let url="test://"+ s;
//test为程序名,注意后面有空格,第二个参数中提供程序的运行位置,具体的可以参考node.js文档。
exec("test "+url, {cwd: process.cwd()+'/XXXX'});
}
}
}
</script>
不过需要注意,在中文windows系统(没有修改过默认字符集的),浏览器里通过自定义协议来启动程序默认传的是gbk的字符集。而不同系统(win10,win7)字符集是不同的。所以就需要对启动程序进行修改。
关于多条命令启动
因为本人写的App需要更新数据库(mysql数据库),所以本人使用mysql的命令进行恢复数据。 奇怪的是child_process的exec竟然不支持多条语句。所以这里我就使用了child_process的spawn。
多条命令之间使用&&间隔,具体的请参照cmd指南(还有别的间隔符,比如| &)
let cmd='cd /d C:/Program Files/MySQL/MySQL Server 5.7/bin && mysql -uXXXXX -pXXXXX abcde </managersystem_user.sql && mysql -uXXXXX -pXXXXX abcde </abcde_xxxx.sql';
cmd+=" && mysql -uXXXXX -pXXXXX abcde < /abcde_routines.sql";
let child = spawn(cmd, {
shell: true
});
//这里还可以输入新的命令与显示cmd返回内容,具体的请参考node.js文档
child.on('exit', ()=> {
});
关于启动参数
//在主进程中
global.sharedObject = {prop1: process.argv}
//渲染进程中
var remote = require('electron').remote,
arguments = remote.getGlobal('sharedObject').prop1;
console.log(arguments);
最后推荐一下苏南大叔的blog
里面有关electron的文章很不错 https://newsn.net