vue结合vue-electron创建应用程序

这里写自定义目录标题

    • 安装electron
      • 第一种方式:vue init electron-vue
      • 第二种方式:vue add electron-builder
    • 启动electron
    • 调试功能:background操作和使用
      • 1、覆盖窗口的菜单上下文、右键菜单
      • 2、监听关闭事件、阻止默认行为
      • 3、创建悬浮窗口
      • 4、窗口置顶
      • 5、绑定全局快捷键
    • 完整代码background.js
    • 打包问题
      • 1、electron-v12.2.3-win32-x64.zip
      • 2、winCodeSign-2.6.0.7z.zip
      • 3、nsis 和 nsis-resources

官方文档:
https://www.electronjs.org/zh/docs/latest/api/menu

安装electron

安装electron有两种方式,两种方式创建的项目结构大不相同

以下内容主要讲解第二种方式,在现有的vue项目中使用electron

// 方式一:基于electron-vue 创建新项目
vue init simulatedgreg/electron-vue 项目名 // 方式二:在现有的vue项目中安装electron包
vue add electron-builder

第一种方式:vue init electron-vue

vue init simulatedgreg/electron-vue 项目名 

在这里插入图片描述
整体结构如下:
在这里插入图片描述
package.json大致的结构如下:

{"name": "name","version": "0.0.1","author": "jmyinjg <jmyinjg@163.com>","description": "An electron-vue project","license": null,"main": "./dist/electron/main.js","scripts": {"build": "node .electron-vue/build.js && electron-builder","build:dir": "node .electron-vue/build.js && electron-builder --dir","build:clean": "cross-env BUILD_TARGET=clean node .electron-vue/build.js","build:web": "cross-env BUILD_TARGET=web node .electron-vue/build.js","dev": "node .electron-vue/dev-runner.js","pack": "npm run pack:main && npm run pack:renderer","pack:main": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.main.config.js","pack:renderer": "cross-env NODE_ENV=production webpack --progress --colors --config .electron-vue/webpack.renderer.config.js","postinstall": ""},"build": {"productName": "midtools","appId": "com.jthe.midtools","directories": {"output": "build"},"files": ["dist/electron/**/*"],"dmg": {"contents": [{"x": 410,"y": 150,"type": "link","path": "/Applications"},{"x": 130,"y": 150,"type": "file"}]},"mac": {"icon": "build/icons/icon.icns"},"win": {"icon": "build/icons/icon.ico"},"linux": {"icon": "build/icons"}},"dependencies": {"@jmyinjg/topsdk": "^1.6.0","ali-oss": "^6.9.0","axios": "^0.18.0","cheerio": "^1.0.0-rc.3","iconv-lite": "^0.5.1","mysql": "^2.18.1","request": "^2.88.2","superagent": "^5.2.2","uuid": "^8.1.0","view-design": "^4.2.0","vue": "^2.5.16","vue-electron": "^1.0.6","vue-router": "^3.0.1","vuex": "^3.0.1","vuex-electron": "^1.0.0"},"devDependencies": {"ajv": "^6.5.0","babel-core": "^6.26.3","babel-loader": "^7.1.4","babel-minify-webpack-plugin": "^0.3.1","babel-plugin-import": "^1.13.0","babel-plugin-transform-runtime": "^6.23.0","babel-preset-env": "^1.7.0","babel-preset-stage-0": "^6.24.1","babel-register": "^6.26.0","cfonts": "^2.1.2","chalk": "^2.4.1","copy-webpack-plugin": "^4.5.1","cross-env": "^5.1.6","css-loader": "^0.28.11","del": "^3.0.0","devtron": "^1.4.0","electron": "^2.0.4","electron-builder": "^20.19.2","electron-debug": "^1.5.0","electron-devtools-installer": "^2.2.4","file-loader": "^1.1.11","html-webpack-plugin": "^3.2.0","mini-css-extract-plugin": "0.4.0","multispinner": "^0.2.1","node-loader": "^0.6.0","style-loader": "^0.21.0","url-loader": "^1.0.1","vue-html-loader": "^1.2.4","vue-loader": "^15.2.4","vue-style-loader": "^4.1.0","vue-template-compiler": "^2.5.16","webpack": "^4.15.1","webpack-cli": "^3.0.8","webpack-dev-server": "^3.1.4","webpack-hot-middleware": "^2.22.2","webpack-merge": "^4.1.3"}
}

第二种方式:vue add electron-builder

vue add electron-builder

整体结构如下:
在这里插入图片描述
package.json大致的结构如下:

{"name": "name","productName": "应用名称","version": "1.5.0","private": true,"scripts": {"serve": "vue-cli-service serve","build": "vue-cli-service build","lint": "vue-cli-service lint","electron:build": "vue-cli-service electron:build","electron:serve": "vue-cli-service electron:serve","postinstall": "electron-builder install-app-deps","postuninstall": "electron-builder install-app-deps"},"main": "background.js","dependencies": {"axios": "~0.21.1","core-js": "~3.15.2","vue": "~3.1.5","vue-axios": "~3.2.4","vue-router": "~4.0.10","vuex": "~4.0.2",......},"devDependencies": {"@vue/cli-plugin-babel": "~4.5.13","@vue/cli-plugin-eslint": "~4.5.13","@vue/cli-plugin-router": "~4.5.13","@vue/cli-plugin-vuex": "~4.5.13","@vue/cli-service": "~4.5.13","@vue/compiler-sfc": "~3.1.5","babel-eslint": "~10.1.0","compression-webpack-plugin": "~6.1.1","electron": "^12.0.0","electron-devtools-installer": "^3.1.0","eslint": "~6.8.0","eslint-plugin-vue": "~7.13.0","postcss": "~8.3.5","vue-cli-plugin-electron-builder": "~2.1.1"},"browserslist": ["> 1%","last 2 versions","not dead"]
}



启动electron

安装完成后,直接启动一下,看看效果

npm run electron:serve

Reload Ctrl+R 刷新
Toggle Developer Tools Ctrl+Shift+I 打开开发者工具
在这里插入图片描述




调试功能:background操作和使用

'use strict'import { app, protocol, BrowserWindow } 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'protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }
])// 创建主窗口
async function createWindow() {const win = new BrowserWindow({width: 800, // 窗口的默认宽度height: 600, // 窗口的默认高度title: '当前窗口的标题',webPreferences: {nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION}})if (process.env.WEBPACK_DEV_SERVER_URL) {await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)// 开发环境下,打开调试工具if (!process.env.IS_TEST) win.webContents.openDevTools()} else {createProtocol('app')// 主窗口创建完成后进入到win.loadURL('app://./index.html')}
}
// 监听整个应用的关闭操作
app.on('window-all-closed', () => {if (process.platform !== 'darwin') {// 关闭应用app.quit()}
})app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()
})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()
})if (isDevelopment) {if (process.platform === 'win32') {process.on('message', (data) => {if (data === 'graceful-exit') {app.quit()}})} else {process.on('SIGTERM', () => {app.quit()})}
}

1、覆盖窗口的菜单上下文、右键菜单

在这里插入图片描述

import {BrowserWindow, Menu } from 'electron'
let mainWin// 主窗口的顶栏菜单
const template = [{label: '后退',click: () => {// 判断 浏览器是否可以后退到前一页面。if (mainWin.webContents.canGoBack()) {// 使浏览器回退到上一个页面。mainWin.webContents.goBack();}}},{label: '前进',click: () => {// 判断 浏览器是否可以前进到下一页面。if (mainWin.webContents.canGoForward()) {// 使浏览器前进到下一个页面。mainWin.webContents.goForward();}}},{label: '刷新',click: () => {mainWin.webContents.reloadIgnoringCache();}},
];// 右键菜单
const contextMenu = Menu.buildFromTemplate([{ label: '复制', role: 'copy' },{ label: '粘贴', role: 'paste' }
]);async function createWindow() {mainWin = new BrowserWindow({...})// 部署顶栏菜单const menu = Menu.buildFromTemplate(template);Menu.setApplicationMenu(menu);// 部署右键菜单mainWin.webContents.on('context-menu', () => {contextMenu.popup({ window: mainWin }); // 在指定窗口上显示上下文菜单});
}

2、监听关闭事件、阻止默认行为

dialog.showMessageBoxSync会返回buttons的索引值,
例如点击了“否”,则choice=0;点击了“是”,则choice=1
注意:如果点击了右上角的叉,则choice=0,所以,“是”只能写在“否”后面
不理解为什么要这么设计

在这里插入图片描述

import { BrowserWindow, dialog } from 'electron'
let mainWinasync function createWindow() {mainWin = new BrowserWindow({...})// 监听 主窗口 右上角的关闭事件mainWin.on('close', (e) => {e.preventDefault(); // 阻止窗口默认的关闭行为/*** 弹出 对话框询问用户是否真的想要退出* 这里的choice 值是buttons的索引,* 例如点击了“否”,则choice=0;点击了“是”,则choice=1* 注意:如果点击了右上角的叉,则choice=0,所以,“是”只能写在“否”后面*/ const choice = dialog.showMessageBoxSync(null, {type: 'info',buttons: ['否', '是'],title: '退出',message: '确定要退出吗?再次开启需重新登录',});// 如果用户选择“是”,则关闭窗口if (choice === 1) {// 关闭窗口并释放内存mainWin.destroy(); // 关闭主窗口app.quit()}})
}

3、创建悬浮窗口

创建第二个窗口——悬浮球,透明背景,点击悬浮球,促使主窗口进入到某个页面

包含的知识点:
1、多个窗口,悬浮球窗口
2、其他窗口促使主窗口路由跳转
3、区分当前环境是electron,还是浏览器
4、窗口的显示和隐藏
在这里插入图片描述

background.js

import { BrowserWindow, ipcMain, screen } from 'electron'let mainWinRoutePath = '/'; // 主窗口的当前路由
let mainWin, ballWinasync function createSBallWindow() {mainWin = new BrowserWindow({...})...
}// 创建 工具球窗口
async function createSBallWindow() {ballWin = new BrowserWindow({width: 65, // 悬浮窗口的宽度 比实际DIV的宽度要多5px,用于处理阴影height: 65, // 悬浮窗口的高度 比实际DIV的高度要多5px,用于处理阴影type: 'toolbar',  //创建的窗口类型为工具栏窗口frame: false,  // 是否创建有边框的窗口(含最大化/最小化/关闭功能),false创建无边框窗口resizable: false, // 是否允许窗口大小缩放movable: true, // 是否可以移动show: true,  // 是否在创建完成后,让窗口显示,如果希望在用户登录后再显示工具球,则设置成false,再通过消息来打开窗口transparent: true, // 设置透明,只有在frame为false时才能生效hasShadow: false, // 是否显示阴影alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前webPreferences: {// devTools: true, // 是否打开调试工具,如果要打开调试,最好把窗口的默认大小调大一些,且不要设置初始位置nodeIntegration: true,contextIsolation: false,}})// 通过获取用户屏幕的宽高来设置悬浮球的初始位置,最好把窗口的默认大小调大一些,且不要设置初始位置const size = screen.getPrimaryDisplay().workAreaSizeballWin.setPosition(size.width - 150, size.height - 200) // 设置悬浮球位置if (process.env.WEBPACK_DEV_SERVER_URL) {await ballWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}ball`)// ballWin.webContents.openDevTools(); // 打开调试工具} else {await ballWin.loadURL('app://./ball.html')}ballWin.on('close', () => {ballWin = null})
}// 监听 open-mainWin-window 消息,  显示 主窗口
ipcMain.on('open-mainWin-window', () => {if (!mainWin) {return}mainWin.maximize()  // 窗口最大化
})// 显示 工具球窗口
ipcMain.on('open-ballWin-window', () => {if (ballWin) {ballWin.show()} else {// 若窗口不存在,则先创建窗口再显示createSBallWindow()ballWin.show()}
});// 隐藏 工具球窗口
ipcMain.on('hide-ballWin-window', () => {ballWin.hide()
});// 保存主窗口的当前路由
ipcMain.on('route-change', (event, route) => {mainWinRoutePath = route;
});// 返回保存的路由信息
ipcMain.handle('get-mainWin-route', () => {return mainWinRoutePath;
});// 进入 主窗口的某个页面
ipcMain.on('change-page', async (event, url) => {if (process.env.WEBPACK_DEV_SERVER_URL) {// 去除url开头的/ 避免造成 http://localhost:8080//...await mainWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}${url.replace(/^\//, '')}`)} else {await mainWin.loadURL(`app://.${url}`)}
})

悬浮球页面 ball.vue

<template><div class="ball" @click="goFast"><!-- dblclick双击 --><span>工具球</span></div>
</template><script>
// 判断是否在 electron 平台的环境当中
let ipcRenderer = null
const isElectron = navigator.userAgent.toLowerCase().indexOf(' electron/') >= 0
if (isElectron) {ipcRenderer = require('electron').ipcRenderer
}export default {name: "ball",data() {return {}},created() {},methods: {goFast() {if (isElectron) {ipcRenderer.invoke('get-mainWin-route').then((route) => {if (route != '/moral/record') {// 消息名称、传参argipcRenderer.send('change-page', '/ball')}// 发送 open-ballWin-window 消息ipcRenderer.send('open-mainWin-window')});}}},
}
</script><style>
body {background: transparent;display: flex;justify-content: center;height: 100%;// 这个是用于 移动窗口/* -webkit-app-region: drag; */
}.ball {width: 60px;height: 60px;line-height: 60px;border-radius: 50%;box-sizing: border-box;background: var(--primary-color);box-shadow: 0 3px 5px 0 rgba(0, 0, 0, 0.4);color: #fff;background: linear-gradient(#40a9ff, #096dd9);text-align: center;cursor: pointer;font-size: 14px;/* -webkit-app-region: no-drag; */
}
</style>

router.js

import { createRouter, createWebHistory } from 'vue-router';
// 判断是否在 electron 平台的环境当中
const isElectron = navigator.userAgent.toLowerCase().indexOf(' electron/') >= 0
let ipcRenderer = null
if (isElectron) {ipcRenderer = require('electron').ipcRenderer
}const router = createRouter({routes: [{path: '/index',component: () => import('@/views/index'),meta: { title: '首页' },},{path: '/ball',component: () => import('@/views/ball'),meta: { title: '工具球' }},...],history: createWebHistory()
});
// 路由守卫
router.beforeEach((to, from, next) => {if (isElectron) {ipcRenderer.send('route-change', to.path)}next()
})export default router;

注意如果使用了screen,一定要引入,否则会启动失败
在这里插入图片描述


4、窗口置顶

// 置顶并显示 主窗口
ipcMain.on('open-mainWin-window', () => {if (!mainWin) {return}mainWin.maximize()  // 窗口最大化// 当 ballWin 失去置顶状态时,将 mainWin 的置顶级别设为较高值mainWin.setAlwaysOnTop(true, 'normal', 1);mainWin.focus(); // 让窗口获得焦点mainWin.setAlwaysOnTop(false); // 如果不希望它一直保持在最上层,可以之后立即取消置顶,即点击其他应用时,当前窗口会下移一层
})

5、绑定全局快捷键

这里会有个问题,注册之后,只要这个窗口没有隐藏,快捷键响应后,还是会触发事件
例如下方是F5,假设你在QQ应用上,点了F5,当前这个应用也会刷新

import { globalShortcut } from 'electron'
let mainWin, ballWin 
...// 全局快捷键 刷新globalShortcut.register('F5', () => {if (mainWin && ballWin) {mainWin.webContents.reloadIgnoringCache();ballWin.webContents.reloadIgnoringCache();}})

完整代码background.js

包含:
1、窗口的菜单、右键菜单、全局快捷键
2、监听窗口的关闭事件,阻止默认行为
3、创建悬浮窗口、窗口的隐藏/显示,促使其他窗口路径跳转
4、窗口置顶事件
5、区分当前环境是electron,还是浏览器

'use strict'import { app, protocol, BrowserWindow, ipcMain, dialog, Menu, screen, globalShortcut } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
import installExtension, { VUEJS_DEVTOOLS } from 'electron-devtools-installer'const path = require('path');
const isDevelopment = process.env.NODE_ENV !== 'production'protocol.registerSchemesAsPrivileged([{ scheme: 'app', privileges: { secure: true, standard: true } }
])let mainWinRoutePath = '/'; // 主窗口的当前路由
let mainWin, ballWin// 主窗口的顶栏菜单
const template = [{label: '后退',click: () => {if (mainWin.webContents.canGoBack()) {mainWin.webContents.goBack();}}},{label: '前进',click: () => {if (mainWin.webContents.canGoForward()) {mainWin.webContents.goForward();}}},{label: '刷新',click: () => {mainWin.webContents.reloadIgnoringCache();}},
];// 右键菜单
const contextMenu = Menu.buildFromTemplate([{ label: '复制', role: 'copy' },{ label: '粘贴', role: 'paste' }
]);async function createWindow() {mainWin = new BrowserWindow({width: 800,height: 800,title: '智慧校园',icon: path.join(__dirname, process.env.VUE_APP_LOGO),webPreferences: {nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION}})const menu = Menu.buildFromTemplate(template);Menu.setApplicationMenu(menu);mainWin.webContents.on('context-menu', () => {contextMenu.popup({ window: mainWin }); // 在指定窗口上显示上下文菜单});if (process.env.WEBPACK_DEV_SERVER_URL) {await mainWin.loadURL(process.env.WEBPACK_DEV_SERVER_URL + 'index')if (!process.env.IS_TEST) mainWin.webContents.openDevTools()} else {createProtocol('app')mainWin.loadURL('app://./index.html')}// 监听 主窗口 右上角的关闭事件mainWin.on('close', (e) => {e.preventDefault(); // 阻止窗口默认的关闭行为// 显示一个对话框询问用户是否真的想要退出const choice = dialog.showMessageBoxSync(null, {type: 'info',buttons: ['否', '是'],title: '退出',message: '确定要退出吗?再次开启需重新登录',});// 如果用户选择“是”,则关闭窗口if (choice === 1) {// 关闭窗口并释放内存mainWin.destroy(); // 关闭主窗口app.quit()}})mainWin.once('ready-to-show', () => {mainWin.show()})
}// 创建 工具球窗口
async function createSBallWindow() {ballWin = new BrowserWindow({width: 65, // 悬浮窗口的宽度 比实际DIV的宽度要多5pxheight: 65, // 悬浮窗口的高度 比实际DIV的高度要多5pxtype: 'toolbar',  //创建的窗口类型为工具栏窗口frame: false,  // 是否创建有边框的窗口(含最大化/最小化/关闭功能),false创建无边框窗口resizable: false, // 是否允许窗口大小缩放movable: true, // 是否可以移动show: true,  // 是否在创建完成后,让窗口显示transparent: true, // 设置透明hasShadow: false, // 是否显示阴影alwaysOnTop: true, // 窗口是否总是显示在其他窗口之前webPreferences: {// devTools: true, // 是否打开调试工具,打开调试则最好调整窗口的大小nodeIntegration: true,contextIsolation: false,}})// 通过获取用户屏幕的宽高来设置悬浮球的初始位置const size = screen.getPrimaryDisplay().workAreaSizeballWin.setPosition(size.width - 150, size.height - 200) // 设置悬浮球位置if (process.env.WEBPACK_DEV_SERVER_URL) {await ballWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}ball`)// ballWin.webContents.openDevTools(); // 打开调试工具} else {await ballWin.loadURL('app://./ball.html')}ballWin.on('close', () => {ballWin = null})
}app.on('window-all-closed', () => {if (process.platform !== 'darwin') {app.quit()}
})// 置顶并显示 主窗口
ipcMain.on('open-mainWin-window', () => {if (!mainWin) {return}mainWin.maximize()  // 窗口最大化if (ballWin) {ballWin.on('always-on-top-changed', (event, isAlwaysOnTop) => {if (isAlwaysOnTop) {// 当 ballWin 处于最顶端时,将 mainWin 的置顶级别设为较低值mainWin.setAlwaysOnTop(true, 'normal', -1);mainWin.focus(); // 让窗口获得焦点} else {// 当 ballWin 失去置顶状态时,将 mainWin 的置顶级别设为较高值mainWin.setAlwaysOnTop(true, 'normal', 1);mainWin.focus();mainWin.setAlwaysOnTop(false); // 如果不希望它一直保持在最上层,可以之后立即取消置顶}})ballWin.setAlwaysOnTop(true, 'normal', 1)} else {mainWin.setAlwaysOnTop(true);mainWin.focus();mainWin.setAlwaysOnTop(false);}
})// 隐藏 主窗口
ipcMain.on('hide-mainWin-window', () => {mainWin.hide()
})// 显示 工具球窗口
ipcMain.on('open-ballWin-window', () => {if (ballWin) {ballWin.show()} else {createSBallWindow()ballWin.show()}
});// 隐藏 工具球窗口
ipcMain.on('hide-ballWin-window', () => {ballWin.hide()
});// 保存主窗口的当前路由
ipcMain.on('route-change', (event, route) => {mainWinRoutePath = route;
});// 返回保存的路由信息
ipcMain.handle('get-mainWin-route', () => {return mainWinRoutePath;
});// 进入 主窗口的某个页面
ipcMain.on('change-page', async (event, url) => {if (process.env.WEBPACK_DEV_SERVER_URL) {// 去除url开头的/ 避免造成 http://localhost:8080//...await mainWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}${url.replace(/^\//, '')}`)} else {await mainWin.loadURL(`app://.${url}`)}
})app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()
})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()//创建球形窗口createSBallWindow()// 注册 全局快捷键 刷新globalShortcut.register('F5', () => {if (mainWin && ballWin) {mainWin.webContents.reloadIgnoringCache();ballWin.webContents.reloadIgnoringCache();}})
})if (isDevelopment) {if (process.platform === 'win32') {process.on('message', (data) => {if (data === 'graceful-exit') {app.quit()}})} else {process.on('SIGTERM', () => {app.quit()})}
}




打包问题

electron-builder打包electron-v12.2.3-win32-x64.zip下载失败,这种情况通常是有electron的4个包,无法下载成功,手动下载后放入到系统对应的文件夹中即可。
分别是
electron-v12.2.3-win32-x64.zip
winCodeSign-2.6.0.7z.zip
nsis-resources3.4.1
nsis-3.4.1

 INFO  Building app with electron-builder:• electron-builder  version=22.14.13 os=10.0.22621• description is missed in the package.json  appPackageFile=D:\web\campus\wisdom-campus-desktop\dist_electron\bundled\package.json• author is missed in the package.json  appPackageFile=D:\web\campus\wisdom-campus-desktop\dist_electron\bundled\package.json• writing effective config  file=dist_electron\builder-effective-config.yaml• packaging       platform=win32 arch=x64 electron=12.2.3 appOutDir=dist_electron\win-unpacked⨯ Get "https://github.com/electron/electron/releases/download/v12.2.3/electron-v12.2.3-win32-x64.zip": proxyconnect tcp: dial tcp :0: connectex: The requested address is not valid in its context.

在这里插入图片描述

按照错误提示,是electron-v12.2.3-win32-x64.zip这个文件下载失败,可以利用报错信息中的https://github.com/electron/electron/releases/download/v12.2.3/electron-v12.2.3-win32-x64.zip
这个地址进行下载,或者到淘宝的镜像地址里去下载,

1、electron-v12.2.3-win32-x64.zip

到淘宝的镜像地址里去下载,https://registry.npmmirror.com/binary.html?path=electron/,依次找到 12.2.3版本下 -> electron-v12.2.3-win32-x64.zip
通常系统会默认隐藏AppData,关闭隐藏即可
下载后,将压缩包解压到这个目录里:
C:\Users\你的用户名\AppData\Local\electron\Cache
在这里插入图片描述
解压后的文件
在这里插入图片描述

2、winCodeSign-2.6.0.7z.zip

https://registry.npmmirror.com/binary.html?path=electron-builder-binaries/winCodeSign-2.6.0/winCodeSign-2.6.0.7z

下载后,将压缩包解压解压到这个目录里:
C:\Users\你的用户名\AppData\Local\electron-builder\Cache\winCodeSign

注意:这里最后一层是winCodeSign,有的文章里显示的是在Cache文件里解压,这样是错误的

在这里插入图片描述
解压后的:
在这里插入图片描述

3、nsis 和 nsis-resources

https://registry.npmmirror.com/binary.html?path=electron-builder-binaries/
在这里插入图片描述

下载后,将2个压缩包都解压到nsis文件价中,没有nsis文件夹就自己创建一个:
C:\Users\你的用户名\AppData\Local\electron-builder\Cache\nsis

在这里插入图片描述
解压后的
在这里插入图片描述
在这里插入图片描述

最后再改一下镜像

用cnpm
npm install -g cnpm --registry=https://registry.npm.taobao.org或者直接用npm
npm config set registry https://registry.npmmirror.com

https://registry.npm.taobao.org 淘宝镜像在2024年1月份已经过期了,目前虽然还能使用,
但是可以观察到,最终还是代理到了 https://registry.npmmirror.com,所以不如直接用 ** https://registry.npmmirror.com**

再次打包electron 应该就没有什么问题了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/731891.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css 背景图片居中显示

background 简写 background: #ffffff url(https://profile-avatar.csdnimg.cn/b9abdd57de464582860bf8ade52373b6_misnice.jpg) center center / 100% no-repeat;效果如图&#xff1a;

关于手机是否支持h264的问题的解决方案

目录 现象 原理 修改内容 现象 开始以为是手机不支持h264的编码 。机器人chatgpt一通乱扯。 后来检查了下手机&#xff0c;明显是有h264嘛。 终于搞定&#xff0c;不枉凌晨三点起来思考 原理 WebRTC 默认使用的视频编码器是VP8和VP9&#xff0c;WebRTC内置了这两种编码器…

Centos 安装 redis【最简单】

Centos7 使⽤ yum 安装 ⾸先安装 scl 源, 再安装 redis &#xff08;因为 Centos7 yum 提供的软件包只有 3.0 版本的 Redis &#xff0c;太老了&#xff0c;我们要安装 redis 5 系列的&#xff09; yum install centos-release-scl-rh yum install rh-redis5-redis 创建符号…

15-单片机烧录FreeTOS操作系统后,程序的执行流程

任务创建 1、在系统上电后&#xff0c;第一个执行的是启动文件由汇编语言编写的复位函数 通过复位函数来初始化系统的时钟&#xff0c;然后再执行__main,初始化系统的堆和栈&#xff0c;然后跳转到main函数 2、在main函数中可以直接进行任务创建操作 因为在FreeRTOS中会自动…

GSEA -- 学习记录

文章目录 brief统计学原理部分其他注意事项转录组部分单细胞部分 brief 上一篇学习记录写了ORA&#xff0c;其中ORA方法只关心差异表达基因而不关心其上调、下调的方向&#xff0c;也许同一条通路里既有显著高表达的基因&#xff0c;也有显著低表达的基因&#xff0c;因此最后…

3.7号freeRtoS

1. 串口通信 配置串口为异步通信 设置波特率&#xff0c;数据位&#xff0c;校验位&#xff0c;停止位&#xff0c;数据的方向 同步通信 在同步通信中&#xff0c;数据的传输是在发送端和接收端之间通过一个共享的时钟信号进行同步的。这意味着发送端和接收端的时钟需要保持…

视频编解码技术介绍 - 基本概念篇

第一章 视频编解码技术介绍 - 基本概念篇 文章目录 前言1. 我的疑问1.1 什么是视频编解码技术1.2 为什么会有视频编解码技术1.3 视频编解码中有哪些核心技术1.4 作为开发者需要重点了解视频编解码中的哪些技术 2. 视频编解码的历史3. 基本概念3.1 像素3.2 分辨率3.3 ppi(像素密…

CorelDRAW下载2024最新版专业的平面设计软件,专注于矢量图形编辑与排版

CorelDRAW是一款功能强大的矢量图形设计软件&#xff0c;广泛应用于标志设计、插画绘制、排版印刷、VI设计、包装设计、网页制作等众多领域。它提供了丰富的绘图工具和特效&#xff0c;使用户能够轻松地创建和编辑复杂的矢量图形。CorelDRAW还支持导入和导出多种文件格式&#…

RabbitMQ 安装使用

文章目录 RabbitMQ 安装使用安装下载 Erlang下载 RabbitMQ 的服务安装好后看是否有 RabbitMQ 的服务开启管理 UIRabbitMQ 端口使用一览图 使用输出最简单的 Hello World&#xff01;生产者定义消费者消费消息小拓展 RabbitMQ 安装使用 安装 下载 Erlang RabbitMQ 是用这个语…

【机器学习300问】30、准确率的局限性在哪里?

一、什么是准确率&#xff1f; 在解答这个问题之前&#xff0c;我们首先得先回顾一下准确率的定义&#xff0c;准确率是机器学习分类问题中一个很直观的指标&#xff0c;它告诉我们模型正确预测的比例&#xff0c;即 还是用我最喜欢的方式&#xff0c;举例子来解释一下&#xf…

倒计时35天

dp预备(来源&#xff1a;b站acm刘春英老师) 1. 2. 3. 4. 5. 6. 7.

13:大数据与Hadoop|分布式文件系统|分布式Hadoop集群

大数据与Hadoop&#xff5c;分布式文件系统&#xff5c;分布式Hadoop集群 Hadoop部署Hadoop HDFS分布式文件系统HDFS部署步骤一&#xff1a;环境准备HDFS配置文件 查官方手册配置Hadoop集群 日志与排错 mapreduce 分布式离线计算框架YARN集群资源管理系统步骤一&#xff1a;安装…

spring boot 集成 mysql ,mybatisplus多数据源

1、需要的依赖&#xff0c;版本自行控制 <dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId> </dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java<…

初阶数据结构之---二叉树的顺序结构-堆

引言 今天要讲的堆&#xff0c;不是操作系统虚拟进程地址空间中&#xff08;malloc&#xff0c;realloc等开空间的位置&#xff09;的那个堆&#xff0c;而是数据结构中的堆&#xff0c;它们虽然名字相同&#xff0c;却是截然不同的两个概念。堆的底层其实是完全二叉树&#x…

【spark operator】spark operator动态分配executor

背景&#xff1a; 之前在使用spark operator的时候必须指定executor的个数&#xff0c;在将任务发布到spark operator后&#xff0c;k8s会根据指定的个数启动executor&#xff0c;但是对于某些spark sql可能并不需要用到那么多executor&#xff0c;在此时executor的数量就不好…

Python快速入门系列-1

Python快速入门系列 第一章: Python简介1.1 Python的历史与发展1.2 Python的优势与特点1.2.1 易学易用1.2.2 动态类型1.2.3 丰富的标准库与第三方库1.2.4 面向对象与函数式编程1.2.5 广泛应用领域 1.3 Python的应用领域 第一章: Python简介 1.1 Python的历史与发展 Python是一…

sizeof和strlen的详细万字解读

sizeof和strlen的对比 sizeof不是函数 侧面证明sizeof不是函数 如果是函数 应该需要有括号 不能落下来 strlen 只针对字符串 包含头文件 string.h 并且这个是个函数 随机数值 sizeof里面有表达式的话 表达式里面是不参与计算的 下面的s求出的是4 就是因为是不参与计算的 不…

AI绘画StableDiffusion实操教程:冰霜旗袍美女

前几天分享了StableDiffusion的入门到精通教程&#xff1a;AI绘画&#xff1a;Stable Diffusion 终极炼丹宝典&#xff1a;从入门到精通 但是还有人就问&#xff1a;安装是安装好了&#xff0c;可是为什么生成的图片和你生成的图片差距那么远呢&#xff1f; 怎么真实感和质感…

pytorch CV入门3-预训练模型与迁移学习

专栏链接&#xff1a;https://blog.csdn.net/qq_33345365/category_12578430.html 初次编辑&#xff1a;2024/3/7&#xff1b;最后编辑&#xff1a;2024/3/8 参考网站-微软教程&#xff1a;https://learn.microsoft.com/en-us/training/modules/intro-computer-vision-pytorc…

GitHub会员充值

GitHub是一个基于Web的代码托管平台&#xff0c;为开发者提供了协作、版本控制和代码管理的工具。它允许个人和团队共同协作开发软件项目&#xff0c;并提供了许多功能&#xff0c;使得代码的管理和维护更加容易 版本控制系统&#xff1a; GitHub使用Git作为其版本控制系统。Gi…