electron,vue开发问题总结

480 阅读5分钟

1.Electron 12中的remote模块已弃用,将在Electron 14中拆除.由@electronic/remote 模块替代

npm install --save @electron/remote

在主线程中使用:

注意:主进程要进行如下设置

webPreferences: {

nodeIntegration: !process.env.ELECTRON_NODE_INTEGRATION, ///process.env.ELECTRON_NODE_INTEGRATION===false

contextIsolation: process.env.ELECTRON_NODE_INTEGRATION,

enableRemoteModule: !process.env.ELECTRON_NODE_INTEGRATION,

}

require(’@electron/remote/main’).initialize()// 开启。这个必须得有。否则也创建不了
require("@electron/remote/main").enable(webContents)

示例:

'use strict'

import {

app,

protocol,

BrowserWindow,

ipcMain,

Menu,

Tray

} from 'electron'

import {

createProtocol

} from 'vue-cli-plugin-electron-builder/lib'

//import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'

const isDevelopment = process.env.NODE_ENV !== 'production'

const path = require('path');

require('@electron/remote/main').initialize()

// 在应用程序准备就绪之前,必须注册方案

protocol.registerSchemesAsPrivileged([{

scheme: 'app',

privileges: {

secure: true,

standard: true

}

}])

let mainWindow = null

let tray = null /******* 创建系托盘 *******/

let CreateTray =

() => {

tray = new Tray(path.join(__static, 'img/app.png'));

const contextMenu = Menu.buildFromTemplate([{

label: '设置',

click: () => {} //打开相应页面

},

{

label: 'Item1',

type: 'radio'

},

{

label: 'Item2',

type: 'radio',

checked: true

},

{

label: '退出',

click: () => {

if (!!mainWindow) {

mainWindow.destroy()

mainWindow

= null

}

if (!!DesktopToolWindow) {

DesktopToolWindow.destroy()

DesktopToolWindow

= null

}

}

}, //我们需要在这里有一个真正的退出(这里直接强制退出)

])

tray.setToolTip('My托盘测试')

tray.setContextMenu(contextMenu)

tray.on('click', () => { //我们这里模拟桌面程序点击通知区图标实现打开关闭应用的功能

console.log("mainWindow.isVisible(", mainWindow.isVisible()) //isMinimized()

mainWindow.show()

})

}

async function createWindow() {

// 创建浏览器窗口。

mainWindow = new BrowserWindow({

width: 710,

height: 492,

resizable: false,

frame: false,

transparent: false,

webPreferences: {

nodeIntegration: !process.env.ELECTRON_NODE_INTEGRATION, ///process.env.ELECTRON_NODE_INTEGRATION===false

contextIsolation: process.env.ELECTRON_NODE_INTEGRATION,

enableRemoteModule: !process.env.ELECTRON_NODE_INTEGRATION,

}

})

mainWindow.setSkipTaskbar(false)

mainWindow.flashFrame(true)

console.log("process.env.WEBPACK_DEV_SERVER_URL", process.env.WEBPACK_DEV_SERVER_URL)

if (process.env.WEBPACK_DEV_SERVER_URL) {

// 如果处于开发模式,请加载开发服务器的url

await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL)

if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()

} else {

createProtocol('app')

// 加载索引,非开发中的html

//mainWindow.loadURL('app://./index.html')

mainWindow.loadURL('app://./index.html')

}

mainWindow.once("ready-to-show", () => {

mainWindow.show();

})

// mainWindow.setMenu(null)

/******* 引入远程模块 *******/

require("@electron/remote/main").enable(mainWindow.webContents);

mainWindow.on('closed', (event) => {

mainWindow = null;

});

// mainWindow.on('close', (event) => {

// event.preventDefault();

// });

// mainWindow.on('show', (event) => {

// event.preventDefault();

// })

// mainWindow.on('hide', (event) => {

// event.preventDefault();

// })

}

// 关闭所有窗口后退出。

app.on('window-all-closed', () => {

// 在macOS上,应用程序及其菜单栏很常见

// 在用户使用Cmd+Q明确退出之前保持活动状态

if (process.platform !== 'darwin') {

app.quit()

}

})

app.on('activate', () => {

//在macOS上,当

//已单击停靠图标,并且没有其他窗口打开。

if (BrowserWindow.getAllWindows().length === 0) createWindow()

})

//此方法将在Electron完成后调用

//初始化并准备好创建浏览器窗口。

//某些API只能在此事件发生后使用。

app.on('ready', async() => {

if (isDevelopment && !process.env.IS_TEST) {

// 安装视图开发工具

try {

//await installExtension(VUEJS_DEVTOOLS)

} catch (e) {

console.error('Vue Devtools failed to install:', e.toString())

}

}

createWindow()

/******* 创建系托盘 *******/

CreateTray()

/******* 监听渲染进程通信 *******/

ipcMain.on('HomePage', (event, arg) => {

console.log(arg)

DesktopTool()

mainWindow.resizable = true

mainWindow.transparent = false

mainWindow.minimize();

event.reply('HomePage-reply', "我是主进程传过去的参数")

})

ipcMain.on('DesktopTool', (event, arg) => {

console.log(arg)

mainWindow.resizable = true

mainWindow.transparent = false

mainWindow.show();

event.reply('DesktopTool-reply', "我是主进程传过去的参数")

})

//

ipcMain.on('CloseClick', (event, arg) => {

console.log(arg)

mainWindow.resizable = true

mainWindow.transparent = false

mainWindow.minimize();

event.reply('CloseClick-reply', "我是CloseClick-reply传过去的参数")

})

})

// 在开发模式下,根据父进程的请求干净地退出。

if (isDevelopment) {

if (process.platform === 'win32') {

process.on('message', (data) => {

if (data === 'graceful-exit') {

app.quit()

}

})

} else {

process.on('SIGTERM', () => {

app.quit()

})

}

}

/******* 以下是渲染进程 *******/ // 开启DesktopToolWindow新窗口

let DesktopToolWindow = null

function DesktopTool() {

if (!!DesktopToolWindow) {

DesktopToolWindow.show()

} else {

CreateDesktopToolWindow()

}

}

async function CreateDesktopToolWindow() {

DesktopToolWindow = new BrowserWindow({

width: 160,

height: 160,

parent: null,

resizable: false,

frame: false,

transparent: true,

alwaysOnTop: true,

webPreferences: {

nodeIntegration: !process.env.ELECTRON_NODE_INTEGRATION, ///process.env.ELECTRON_NODE_INTEGRATION===false

contextIsolation: process.env.ELECTRON_NODE_INTEGRATION,

enableRemoteModule: !process.env.ELECTRON_NODE_INTEGRATION,

}

})

if (process.env.WEBPACK_DEV_SERVER_URL) {

// 如果处于开发模式,请加载开发服务器的url

await DesktopToolWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '#/ztdada/desktoptool')

// if (!process.env.IS_TEST) //DesktopToolWindow.webContents.openDevTools()

} else {

createProtocol('app')

// 加载索引,非开发中的html

await DesktopToolWindow.loadURL('app://./index.html#/ztdada/desktoptool')

//await DesktopToolWindow.loadURL("bilibili.com/")

}

// DesktopToolWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '#/ztdada/desktoptool');

DesktopToolWindow.setIgnoreMouseEvents(false)

DesktopToolWindow.setSkipTaskbar(true)

// DesktopToolWindow.loadURL("bilibili.com/")

//DesktopToolWindow.loadFile('../src/pages/DesktopToolPage/index.vue')

DesktopToolWindow.on('closed', () => {

DesktopToolWindow = null

})

}

在渲染进程使用(.vue文件):

注意:在vue文件中直接require("electron")会报错,需要这样引入

const { require } = window;
const { ipcRenderer } = require("electron");
const { BrowserWindow } = require("@electron/remote");

或者这样引入

const { ipcRenderer } =  window.require("electron");
const { BrowserWindow } =  window.require("@electron/remote");

示例:

2.@electron/remote经过上面配置在开发环境可以正常使用,但打包时,还需做以下配置,否则打包后运行软件会报错

官网上是这样解释:

本机模块受支持,并且应在不进行任何配置的情况下工作,前提是启用了节点集成。如果出现错误,可能需要将本机依赖项设置为外部网页包(打开新窗口)。应该会自动找到它,但可能不会。为此,请使用externals选项.

nklayman.github.io/vue-cli-plu…

 externals: ['@electron/remote'],
 nodeModulesPath: ['../../node_modules', './node_modules'],

在vue.config.js文件中:

  pluginOptions: {
        'style-resources-loader': {
            preProcessor: 'scss',
            patterns: [path.resolve(__dirname, './src/assets/globalscss/*.scss'), ]
        },
        electronBuilder: {
            externals: ['@electron/remote'],
            nodeModulesPath: ['../../node_modules', './node_modules'],
            builderOptions: {
                productName: "volodya",
                appId: 'volodya',
                win: {
                    "target": [
                        "nsis"
                    ],
                    icon: 'src/assets/img/app.png',
                    "requestedExecutionLevel": "requireAdministrator",
                    'legalTrademarks': 'http://www.baidu.com/'
                },
                "nsis": {
                    "installerIcon": "src/assets/ico/app.ico",
                    "uninstallerIcon": "src/assets/ico/app.ico",
                    "uninstallDisplayName": "CPU Monitor",
                    "license": "src/assets/ico/license.html",
                    "oneClick": false,
                    "allowToChangeInstallationDirectory": true,
                    "displayLanguageSelector": true,

                },
                "mac": {
                    "icon": "src/assets/ico/app.icns", // 应用程序图标
                    "artifactName": "volodya", // 应用程序包名
                    "target": [
                        "dmg",
                        "zip"
                    ]
                },
                'dmg': {
                    'title': 'volodya',
                    'icon': 'src/assets/ico/app.icns',
                    'contents': [{
                            'x': 110,
                            'y': 150
                        },
                        {
                            'x': 240,
                            'y': 150,
                            'type': 'link',
                            'path': '/Applications'
                        }
                    ],
                    'window': {
                        'x': 400,
                        'y': 400
                    }
                }
            },
        },
    },

3.在创建windows系统托盘时,let tray = null要设置为全局变量,否则会被回收机制清除,导致系统托盘自动消失的问题。

注意: __dirname=== dist_electron ,__static === public,例如:app.png图片在vue-cli4创建的vue项目的public/img

文件下,在electron项目里使用

path.join(__static, 'img/app.png')

示例:

/******* 创建系托盘 *******/
let tray = null 
let CreateTray =
    () => {
        tray = new Tray(path.join(__static, 'img/app.png'));
        const contextMenu = Menu.buildFromTemplate([{
                label: '设置',
                click: () => {} //打开相应页面
            },
            {
                label: 'Item1',
                type: 'radio'
            },
            {
                label: 'Item2',
                type: 'radio',
                checked: true
            },
            {
                label: '退出',
                click: () => {
                    if (!!mainWindow) {
                        mainWindow.destroy()
                        mainWindow
                            = null
                    }
                    if (!!DesktopToolWindow) {
                        DesktopToolWindow.destroy()
                        DesktopToolWindow
                            = null
                    }
                }
            }, //我们需要在这里有一个真正的退出(这里直接强制退出)
        ])
        tray.setToolTip('My托盘测试')
        tray.setContextMenu(contextMenu)
        tray.on('click', () => { //我们这里模拟桌面程序点击通知区图标实现打开关闭应用的功能
            console.log("mainWindow.isVisible(", mainWindow.isVisible()) //isMinimized()
            mainWindow.show()

        })

    }

调用:

CreateTray()

4.vue,router,electron结合使用

注意:路由要用hash模式,不可用history模式

router/index.js

/**
 * Модуль роутера приложения
 */

import Vue from 'vue';
import VueRouter from 'vue-router';
import initListners from './initListners';
import listners from './listners';
import Home from '@/views/Home/index'
Vue.use(VueRouter)

const routes = [
    /* {
        path: '/',
        redirect: '/ztdada/home',
    }, */
    {
        path: '/ztdada/login',
        name: 'Login',
        component: () =>
            import ('@/views/Login/index'),
        meta: {
            Title: "登录",

        }

    }, {
        path: '/',
        name: 'Home',
        component: Home,
        // component: () =>
        //     import ('@/views/Home/index'),
        meta: {
            Title: "首页",

        }
    }, {
        path: '/ztdada/desktoptool',
        name: 'DesktopTool',
        component: () =>
            import ('@/views/DesktopTool/index'),
        meta: {
            Title: "首页",

        }
    }, {
        path: '*',
        component: () =>
            import ('@/views/Error/index'),
        hidden: true
    }
];

const router = new VueRouter({
    // mode: 'history',
    // base: process.env.BASE_URL,
    routes
})

export default initListners(router, listners);

在electron项目中使用:

background.js

“/”根路径页面"http://192.168.252.1:8080/#/"使用

if (process.env.WEBPACK_DEV_SERVER_URL) {
        // 如果处于开发模式,请加载开发服务器的url
        await mainWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
        if (!process.env.IS_TEST) mainWindow.webContents.openDevTools()
    } else {
        createProtocol('app')
            // 加载索引,非开发中的html
            //mainWindow.loadURL('app://./index.html')
        mainWindow.loadURL('app://./index.html')
    }

路由页面"http://192.168.252.1:8080/#/ztdada/desktoptool"使用

 if (process.env.WEBPACK_DEV_SERVER_URL) {
        // 如果处于开发模式,请加载开发服务器的url
        await DesktopToolWindow.loadURL(process.env.WEBPACK_DEV_SERVER_URL + '#/ztdada/desktoptool')
            // if (!process.env.IS_TEST) //DesktopToolWindow.webContents.openDevTools()
    } else {
        createProtocol('app')
            // 加载索引,非开发中的html
        await DesktopToolWindow.loadURL('app://./index.html#/ztdada/desktoptool')
            //await DesktopToolWindow.loadURL("https://bilibili.com/")
    }

示例:

生产环境中electron加载路由页面