1. 使用electron-vue新建基于vue
的electron
环境,更多配置请访问源项目
npm i -g vue-cli
vue init simulatedgreg/electron-vue my-project
cd my-project
npm i
npm run dev
2. 打通electron
主进程与渲染进程的通信
定义常量作为
channel
,也就是事件类型名称
const CLIENT_NORMAL_MSG = 'CLIENT_NORMAL_MSG' // 渲染进程发出消息类型
const CRAWLER_NORMAL_MSG = 'CRAWLER_NORMAL_MSG' // 主进程发出消息类型
渲染进程
在渲染进程中,使用vue plugin
的形式,具体参见vue
官方文档插件
ipcRenderer
是eventEmitter的一个实例,在渲染进程中使用,你可以通过它来像主进程发送同步和异步消息,也可以通过它来接收来自主进程的消息
const { ipcRenderer } = require('electron')
const ipcService = Object.create(null)
const callbackCache = []
ipcService.install = Vue => {
Vue.prototype.$ipcRenderer = {
send: (msgType, msgData) => {
ipcRenderer.send(CLIENT_NORMAL_MSG, {
type: msgType,
data: msgData,
})
},
on: (type, callback) => {
callbackCache.push({
type,
callback,
})
}
}
ipcRenderer.on(CRAWLER_NORMAL_MSG, (sender, msg) => {
callbackCache.forEach(cache => {
if (cache.type === msg.type) {
cache.callback && cache.callback(msg.data)
}
})
}) // 监听主进程的消息
}
export default ipcService
在vue
项目中通过this.$ipcRenderer.on
的方式添加主进程发送消息的监听,通过this.$ipcRenderer.send
的方式向主进程发送消息,保证发出消息均为CLIENT_NORMAL_MSG
类型,收到消息均为CRAWLER_NORMAL_MSG
,通过消息中的二级固定参数type
来区分具体类型,并可以通过detach
的方式来取消特定的类型的消息的监听
最后在Vue
的入口文件,也就是渲染进程的入口文件使用上面定义的插件 Vue.use(ipcService)
渲染进程中的配置完成
主进程
使用class
的方式来定义,需要传入两个参数来实例化这个class
,需要传入两个参数,listener
为监听消息者,sender
为发送消息者
ipcMsgHandler
中包含了所有的handler
,为其传入this
以便能够在其中向渲染进程发送消息
import ipcMsgHandler from './ipcMsgHandler'
export default class Ipc {
constructor(listener, sender) {
this.listener = listener
this.sender = sender
this.addListener(CLIENT_NORMAL_MSG, this.handleFn.bind(this))
this.handlerList = ipcMsgHandler(this)
}
handleFn(event, data) {
try {
this.handlerList[data.type](event, data.data)
} catch (error) {
console.error('handler event error:' + error.message)
}
}
addListener(chanel, cb) {
this.listener.on(chanel, cb)
}
_sendMsg(chanel, msgBody) {
this.sender.send(chanel, msgBody)
}
sendToClient(type, data) {
this._sendMsg(CRAWLER_NORMAL_MSG, {
type,
data,
})
}
}
初始状态下ipcMsgHandler.js
文件
export default _ipc => ({})
在主进程的入口文件(/src/main/index.js
)中对Ipc
这个class
实例化,其中需要使用的listener
为ipcMain
,ipcMain
和ipcRenderer
不同,它只负责对消息的监听,不复杂发送消息,这里需要入口文件中的mainWindow
下的webContents
作为消息的发送者,所以需要在mainWindow
创建成功之后再进行Ipc
的实例化
// ...
function createWindow() {
mainWindow = new BrowserWindow({
// ...
});
new IpcMgr(ipcMain, mainWindow.webContents)
}
3. 完成具体功能开发
引入element-ui
,使用babel
配置css
按需加载,具体配置方式element-ui官网
分析掘金首页数据来源
掘金首页七种分类下数据均来自一个接口,https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit=20&category=xxx
,通过category
进行分类的区分
渲染进程开发
在App.js
中,在进入页面和切换分类时向主进程发送消息
// ...
methods: {
startRequest() {
this.$ipcRenderer.send('start-request', this.activeCategory)
},
onRequestBack() {
this.$ipcRenderer.on('request-back', data => {
// todo...
})
},
}
主进程开发
现在渲染进程中已经定义了两种消息类型start-request
和request-back
,start-request
告诉主进程开始执行任务,完成后request-back
告诉渲染进程任务完成,渲染进程收到消息后通过收到的数据来对页面进行操作。
在ipcMsgHandler.js
中进行拓展,使用axios
对接口内容进行抓取
import axios from 'axios'
const handlerList = _ipc => ({
['start-request'](event, category) {
const requestBack = data => {
_ipc.sendToClient('request-back', data)
}
axios.get(`https://timeline-merger-ms.juejin.im/v1/get_entry_by_rank?src=web&limit=20&category=${category}`)
.then(r => {
if(r.status === 200) {
requestBack({
success: true,
rows: r.data.d.entrylist
})
} else {
requestBack({
success: false,
error: `server error code: ${r.status}`
})
}
})
.catch(e => requestBack({
success: false,
error: `server error code: ${e.status} msg: ${e.message}`
}))
}
})
请求完成后,通过requestBack
向渲染进程发送消息,渲染页面,操作样式调整,页面看起来大概是这样。
4. 增加链接跳转到默认浏览器
在该项目中如果直接使用window.open
的方式来打开的话,它会新弹出一个electron
窗口,所有连接跳转也需要用到ipc
的方式
在electron
中,有一个shell
对象,它提供一个openExternal
的方法来在默认浏览器中打开链接
在ipcMsgHandler.js
中新增以下内容
const { shell } = require('electron')
export default _ipc => ({
['open-shell'](event, url) {
shell.openExternal(url)
},
// ...
})
现在就可以在vue
中通过this.$ipcRenderer.send('open-shell', url)
的方式来在默认浏览器中打开链接了
一个通过打通IPC
通信方式的掘金首页概览客户端就完成了,通过npm run build
就可以对这个应用进行打包了
PS: 其实在electron
中是可以支持跨域访问的,只需要在创建窗口的时候加上一下配置项就行了,不过结果其实并不重要,重要的是过程了
webPreferences: {
webSecurity: false,
}
以上代码都可以在github上找到,欢迎star~~~