记录一下使用vue+electron开发

记录一下使用vue+electron开发

之前早就听过这个工具但是因为一直公司没这种项目所以一直没有接触过,近期公司接了个一个小工具的开发,要求做成windows桌面应用,所以机会来了

先看一眼 官网 image.png

因为技术比较烂看不太懂,所以就开始七七八八找一些资料了。目前是打算用vue2来开发,发现 electron-vue和electron-builder比较合适。但是electron-vue配置总有些问题,目前就打算用electron-builder来开发。

先新建一个普通vue2项目,然后 yarn add electron-builder就好了,版本好像只能13.0最高。

首先要配置在web上能使用node模块,不配置的话electron的一些模块无法使用。

src/background.js

const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: true,  //web中能使用node模块
      contextIsolation: false //不知道是啥可以在文档中看看
    }
  })

vue.config.js

const { defineConfig } = require('@vue/cli-service')
  module.exports = defineConfig({
    transpileDependencies: true,
    pluginOptions: {
      electronBuilder: {
        nodeIntegration: true //web中能使用node模块,这里不配置会无法在渲染进程中使用electron模块
      }
    }
})

配置好后就可以使用electron的各种模块了, electron中有两种进程,主进程和渲染进程, 主进程是background.js中执行的东西,渲染进程就是不在主进程中运行的代码(目前我这样理解的,比较好记,大佬勿喷)

目前发现的比较好参考的文档: 腾讯开发者文档

还有就是w3cschool的了 主要他这里会写,哪些模块是主进程中可使用,哪些是渲染进程中可使用。

image.png
模块

开始试试一些模块: 首先main.js先挂载一下,当然你也可以在vue文件中引入一下来使用

import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'
import electron from 'electron'

Vue.config.productionTip = false
Vue.prototype.$electron = electron
new Vue({
  router,
  store,
  render: h => h(App)
}).$mount('#app')
ipc渲染器 | ipcRenderer (渲染进程)

从呈现程序进程到主进程异步通信。 使用send可以发送信息到主进程,使用on可以接收主进程发过来的消息。感觉有点像eventbus,emit,emit,on的感觉。

<template>
  <div class="home">
    <img alt="Vue logo"
         src="../assets/logo.png">
    <button @click="sendToMain">发送到主线程</button>
  </div>
</template>

<script>
// import { ipcRenderer } from 'electron'
export default {
  name: 'HomeView',
  components: {
  },
  methods: {
    sendToMain () {
      this.$electron.ipcRenderer.send('helloworld', '二狗子') //发送消息
    }
  },
  created(){
      this.$electron.ipcRenderer.on('reply', (event,arg)=>{ //接收消息
         console.log(arg)
      })
  }
}
</script>

ipcMain (主进程)

从主进程到呈现程序进程异步通信。

import { app, protocol, ipcMain, BrowserWindow } from 'electron'
async function createWindow () {
  // Create the browser window.
  const win = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {

      // Use pluginOptions.nodeIntegration, leave this alone
      // See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
      nodeIntegration: true,
      contextIsolation: false
    }
  })
  // 接收消息
  ipcMain.on('helloworld', (event, arg) => {
    console.log(arg) // prints "二狗子"
    event.sender.send('reply', 'pong')
  })
  if (process.env.WEBPACK_DEV_SERVER_URL) {
    // Load the url of the dev server if in development mode
    await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
    if (!process.env.IS_TEST) win.webContents.openDevTools()
  } else {
    createProtocol('app')
    // Load the index.html when not in development
    win.loadURL('app://./index.html')
  }
}

点击发送到主进程按钮后,vscode中的终端会显示主进程的log消息,electron的浏览器控制台中会显示 渲染进程的消息。

image.png
remote模块(渲染进程)

可以用来打开新窗口,必须在src/background.js里开启enableRemoteModule。 不建议使用remote,建议在主进程使用BrowserWindow模块直接创建窗口。

const win = new this.$electron.remote.BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false,
          enableRemoteModule: true
        }
      })

使用

<template>
  <div class="home">
    <button @click="openNew">打开新窗口</button>
  </div>
</template>

<script>
//判断是开发模式还是别的模式,定义加载的路径
const winURL = process.env.NODE_ENV === 'development'
  ? 'http://localhost:8082'
  // eslint-disable-next-line node/no-path-concat
  : `file://${__dirname}/index.html`
export default {
  name: 'HomeView',
  components: {
  },
  methods: {
    openNew () {
      console.log(this.$electron)
      const win = new this.$electron.remote.BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false,
          enableRemoteModule: true
        }
      })
      //跳转到路由,这个可以封装成方法,但是不建议使用remote来创建窗口,据说比较耗性能
      win.loadURL(winURL + '/#/' + 'about')
    }
  }
}
</script>

效果

image.png
使用vuex-electron插件

tip:直接使用vuex的话多窗口之前的vuex数据是独立的,不会同步。

使用过程中有些坑, 首先需要根据他的官方文档配置,

Installation

Installation of the Vuex Electron easy as 1-2-3.

  1. Install package with using of yarn or npm:

    yarn install vuex-electron
    

    or

    npm install vuex-electron
    
  2. Include plugins in your Vuex store::

    import Vue from "vue"
    import Vuex from "vuex"
    
    import { createPersistedState, createSharedMutations } from "vuex-electron"
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      // ...
      plugins: [
        createPersistedState(),
        createSharedMutations()
      ],
      // ...
    })
    
  3. In case if you enabled createSharedMutations() plugin you need to create an instance of store in the main process. To do it just add this line into your main process (for example src/main.js):

    import './path/to/your/store'
    
  4. Well done you did it! The last step is to add the star to this repo 😄`

配置完后,需要确保各个窗口之间,都开启了nodeIntegration、enableRemoteModule。如果没开启将会引起报错窗口空白(重要)。网上大多资料没有指出这一点,说多了都是泪。

const win = new this.$electron.remote.BrowserWindow({
        width: 800,
        height: 600,
        webPreferences: {
          nodeIntegration: true,
          contextIsolation: false,
          enableRemoteModule: true
        }
      })

最后看看使用效果,各个窗口之间的vuex数据是同步的。

image.png

到这里我们基本可以实现的功能有,主进程渲染进程使用vuex、开多个窗口(路由)、主进程渲染进程之间通信、渲染进程通过主进程与另一个渲染进程通信。

另外可以结合electron腾讯开发者手册及其他博客来看各种属性实例方法等,里面有一些比较常用的东西。 例如,自定义标题栏、拖动与可缩放大小、托盘、模态窗口(父子窗口)等

image.png

electron还有很多模块,后续用到会慢慢在这里补充。