vue結(jié)合vue-electron創(chuàng)建應(yīng)用程序小結(jié)
官方文檔:https://www.electronjs.org/zh/docs/latest/api/menu
安裝electron
安裝electron有兩種方式,兩種方式創(chuàng)建的項(xiàng)目結(jié)構(gòu)大不相同
以下內(nèi)容主要講解第二種方式,在現(xiàn)有的vue項(xiàng)目中使用electron
// 方式一:基于electron-vue 創(chuàng)建新項(xiàng)目 vue init simulatedgreg/electron-vue 項(xiàng)目名 // 方式二:在現(xiàn)有的vue項(xiàng)目中安裝electron包 vue add electron-builder
第一種方式:vue init electron-vue
vue init simulatedgreg/electron-vue 項(xiàng)目名

整體結(jié)構(gòu)如下:

package.json大致的結(jié)構(gòu)如下:
{
"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
整體結(jié)構(gòu)如下:

package.json大致的結(jié)構(gòu)如下:
{
"name": "name",
"productName": "應(yīng)用名稱",
"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"
]
}啟動(dòng)electron
安裝完成后,直接啟動(dòng)一下,看看效果
npm run electron:serve
Reload Ctrl+R 刷新
Toggle Developer Tools Ctrl+Shift+I 打開開發(fā)者工具

調(diào)試功能: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 } }
])
// 創(chuàng)建主窗口
async function createWindow() {
const win = new BrowserWindow({
width: 800, // 窗口的默認(rèn)寬度
height: 600, // 窗口的默認(rèn)高度
title: '當(dāng)前窗口的標(biāo)題',
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)
// 開發(fā)環(huán)境下,打開調(diào)試工具
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
createProtocol('app')
// 主窗口創(chuàng)建完成后進(jìn)入到
win.loadURL('app://./index.html')
}
}
// 監(jiān)聽整個(gè)應(yīng)用的關(guān)閉操作
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
// 關(guān)閉應(yīng)用
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: () => {
// 判斷 瀏覽器是否可以后退到前一頁(yè)面。
if (mainWin.webContents.canGoBack()) {
// 使瀏覽器回退到上一個(gè)頁(yè)面。
mainWin.webContents.goBack();
}
}
},
{
label: '前進(jìn)',
click: () => {
// 判斷 瀏覽器是否可以前進(jìn)到下一頁(yè)面。
if (mainWin.webContents.canGoForward()) {
// 使瀏覽器前進(jìn)到下一個(gè)頁(yè)面。
mainWin.webContents.goForward();
}
}
},
{
label: '刷新',
click: () => {
mainWin.webContents.reloadIgnoringCache();
}
},
];
// 右鍵菜單
const contextMenu = Menu.buildFromTemplate([
{ label: '復(fù)制', 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、監(jiān)聽關(guān)閉事件、阻止默認(rèn)行為
dialog.showMessageBoxSync會(huì)返回buttons的索引值,
例如點(diǎn)擊了“否”,則choice=0;點(diǎn)擊了“是”,則choice=1
注意:如果點(diǎn)擊了右上角的叉,則choice=0,所以,“是”只能寫在“否”后面
不理解為什么要這么設(shè)計(jì)

import { BrowserWindow, dialog } from 'electron'
let mainWin
async function createWindow() {
mainWin = new BrowserWindow({
...
})
// 監(jiān)聽 主窗口 右上角的關(guān)閉事件
mainWin.on('close', (e) => {
e.preventDefault(); // 阻止窗口默認(rèn)的關(guān)閉行為
/**
* 彈出 對(duì)話框詢問(wèn)用戶是否真的想要退出
* 這里的choice 值是buttons的索引,
* 例如點(diǎn)擊了“否”,則choice=0;點(diǎn)擊了“是”,則choice=1
* 注意:如果點(diǎn)擊了右上角的叉,則choice=0,所以,“是”只能寫在“否”后面
*/
const choice = dialog.showMessageBoxSync(null, {
type: 'info',
buttons: ['否', '是'],
title: '退出',
message: '確定要退出嗎?再次開啟需重新登錄',
});
// 如果用戶選擇“是”,則關(guān)閉窗口
if (choice === 1) {
// 關(guān)閉窗口并釋放內(nèi)存
mainWin.destroy(); // 關(guān)閉主窗口
app.quit()
}
})
}3、創(chuàng)建懸浮窗口
創(chuàng)建第二個(gè)窗口——懸浮球,透明背景,點(diǎn)擊懸浮球,促使主窗口進(jìn)入到某個(gè)頁(yè)面
包含的知識(shí)點(diǎn):
1、多個(gè)窗口,懸浮球窗口
2、其他窗口促使主窗口路由跳轉(zhuǎn)
3、區(qū)分當(dāng)前環(huán)境是electron,還是瀏覽器
4、窗口的顯示和隱藏

background.js
import { BrowserWindow, ipcMain, screen } from 'electron'
let mainWinRoutePath = '/'; // 主窗口的當(dāng)前路由
let mainWin, ballWin
async function createSBallWindow() {
mainWin = new BrowserWindow({
...
})
...
}
// 創(chuàng)建 工具球窗口
async function createSBallWindow() {
ballWin = new BrowserWindow({
width: 65, // 懸浮窗口的寬度 比實(shí)際DIV的寬度要多5px,用于處理陰影
height: 65, // 懸浮窗口的高度 比實(shí)際DIV的高度要多5px,用于處理陰影
type: 'toolbar', //創(chuàng)建的窗口類型為工具欄窗口
frame: false, // 是否創(chuàng)建有邊框的窗口(含最大化/最小化/關(guān)閉功能),false創(chuàng)建無(wú)邊框窗口
resizable: false, // 是否允許窗口大小縮放
movable: true, // 是否可以移動(dòng)
show: true, // 是否在創(chuàng)建完成后,讓窗口顯示,如果希望在用戶登錄后再顯示工具球,則設(shè)置成false,再通過(guò)消息來(lái)打開窗口
transparent: true, // 設(shè)置透明,只有在frame為false時(shí)才能生效
hasShadow: false, // 是否顯示陰影
alwaysOnTop: true, // 窗口是否總是顯示在其他窗口之前
webPreferences: {
// devTools: true, // 是否打開調(diào)試工具,如果要打開調(diào)試,最好把窗口的默認(rèn)大小調(diào)大一些,且不要設(shè)置初始位置
nodeIntegration: true,
contextIsolation: false,
}
})
// 通過(guò)獲取用戶屏幕的寬高來(lái)設(shè)置懸浮球的初始位置,最好把窗口的默認(rèn)大小調(diào)大一些,且不要設(shè)置初始位置
const size = screen.getPrimaryDisplay().workAreaSize
ballWin.setPosition(size.width - 150, size.height - 200) // 設(shè)置懸浮球位置
if (process.env.WEBPACK_DEV_SERVER_URL) {
await ballWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}ball`)
// ballWin.webContents.openDevTools(); // 打開調(diào)試工具
} else {
await ballWin.loadURL('app://./ball.html')
}
ballWin.on('close', () => {
ballWin = null
})
}
// 監(jiān)聽 open-mainWin-window 消息, 顯示 主窗口
ipcMain.on('open-mainWin-window', () => {
if (!mainWin) {
return
}
mainWin.maximize() // 窗口最大化
})
// 顯示 工具球窗口
ipcMain.on('open-ballWin-window', () => {
if (ballWin) {
ballWin.show()
} else {
// 若窗口不存在,則先創(chuàng)建窗口再顯示
createSBallWindow()
ballWin.show()
}
});
// 隱藏 工具球窗口
ipcMain.on('hide-ballWin-window', () => {
ballWin.hide()
});
// 保存主窗口的當(dāng)前路由
ipcMain.on('route-change', (event, route) => {
mainWinRoutePath = route;
});
// 返回保存的路由信息
ipcMain.handle('get-mainWin-route', () => {
return mainWinRoutePath;
});
// 進(jìn)入 主窗口的某個(gè)頁(yè)面
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}`)
}
})懸浮球頁(yè)面 ball.vue
<template>
<div class="ball" @click="goFast">
<!-- dblclick雙擊 -->
<span>工具球</span>
</div>
</template>
<script>
// 判斷是否在 electron 平臺(tái)的環(huán)境當(dāng)中
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') {
// 消息名稱、傳參arg
ipcRenderer.send('change-page', '/ball')
}
// 發(fā)送 open-ballWin-window 消息
ipcRenderer.send('open-mainWin-window')
});
}
}
},
}
</script>
<style>
body {
background: transparent;
display: flex;
justify-content: center;
height: 100%;
// 這個(gè)是用于 移動(dòng)窗口
/* -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 平臺(tái)的環(huán)境當(dāng)中
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: '首頁(yè)' },
},
{
path: '/ball',
component: () => import('@/views/ball'),
meta: { title: '工具球' }
},
...
],
history: createWebHistory()
});
// 路由守衛(wèi)
router.beforeEach((to, from, next) => {
if (isElectron) {
ipcRenderer.send('route-change', to.path)
}
next()
})
export default router;注意:如果使用了screen,一定要引入,否則會(huì)啟動(dòng)失敗

4、窗口置頂
// 置頂并顯示 主窗口
ipcMain.on('open-mainWin-window', () => {
if (!mainWin) {
return
}
mainWin.maximize() // 窗口最大化
// 當(dāng) ballWin 失去置頂狀態(tài)時(shí),將 mainWin 的置頂級(jí)別設(shè)為較高值
mainWin.setAlwaysOnTop(true, 'normal', 1);
mainWin.focus(); // 讓窗口獲得焦點(diǎn)
mainWin.setAlwaysOnTop(false); // 如果不希望它一直保持在最上層,可以之后立即取消置頂,即點(diǎn)擊其他應(yīng)用時(shí),當(dāng)前窗口會(huì)下移一層
})5、綁定全局快捷鍵
這里會(huì)有個(gè)問(wèn)題,注冊(cè)之后,只要這個(gè)窗口沒有隱藏,快捷鍵響應(yīng)后,還是會(huì)觸發(fā)事件
例如下方是F5,假設(shè)你在QQ應(yīng)用上,點(diǎn)了F5,當(dāng)前這個(gè)應(yīng)用也會(huì)刷新
import { globalShortcut } from 'electron'
let mainWin, ballWin
...
// 全局快捷鍵 刷新
globalShortcut.register('F5', () => {
if (mainWin && ballWin) {
mainWin.webContents.reloadIgnoringCache();
ballWin.webContents.reloadIgnoringCache();
}
})完整代碼background.js
包含:
1、窗口的菜單、右鍵菜單、全局快捷鍵
2、監(jiān)聽窗口的關(guān)閉事件,阻止默認(rèn)行為
3、創(chuàng)建懸浮窗口、窗口的隱藏/顯示,促使其他窗口路徑跳轉(zhuǎn)
4、窗口置頂事件
5、區(qū)分當(dāng)前環(huán)境是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 = '/'; // 主窗口的當(dāng)前路由
let mainWin, ballWin
// 主窗口的頂欄菜單
const template = [
{
label: '后退',
click: () => {
if (mainWin.webContents.canGoBack()) {
mainWin.webContents.goBack();
}
}
},
{
label: '前進(jìn)',
click: () => {
if (mainWin.webContents.canGoForward()) {
mainWin.webContents.goForward();
}
}
},
{
label: '刷新',
click: () => {
mainWin.webContents.reloadIgnoringCache();
}
},
];
// 右鍵菜單
const contextMenu = Menu.buildFromTemplate([
{ label: '復(fù)制', 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')
}
// 監(jiān)聽 主窗口 右上角的關(guān)閉事件
mainWin.on('close', (e) => {
e.preventDefault(); // 阻止窗口默認(rèn)的關(guān)閉行為
// 顯示一個(gè)對(duì)話框詢問(wèn)用戶是否真的想要退出
const choice = dialog.showMessageBoxSync(null, {
type: 'info',
buttons: ['否', '是'],
title: '退出',
message: '確定要退出嗎?再次開啟需重新登錄',
});
// 如果用戶選擇“是”,則關(guān)閉窗口
if (choice === 1) {
// 關(guān)閉窗口并釋放內(nèi)存
mainWin.destroy(); // 關(guān)閉主窗口
app.quit()
}
})
mainWin.once('ready-to-show', () => {
mainWin.show()
})
}
// 創(chuàng)建 工具球窗口
async function createSBallWindow() {
ballWin = new BrowserWindow({
width: 65, // 懸浮窗口的寬度 比實(shí)際DIV的寬度要多5px
height: 65, // 懸浮窗口的高度 比實(shí)際DIV的高度要多5px
type: 'toolbar', //創(chuàng)建的窗口類型為工具欄窗口
frame: false, // 是否創(chuàng)建有邊框的窗口(含最大化/最小化/關(guān)閉功能),false創(chuàng)建無(wú)邊框窗口
resizable: false, // 是否允許窗口大小縮放
movable: true, // 是否可以移動(dòng)
show: true, // 是否在創(chuàng)建完成后,讓窗口顯示
transparent: true, // 設(shè)置透明
hasShadow: false, // 是否顯示陰影
alwaysOnTop: true, // 窗口是否總是顯示在其他窗口之前
webPreferences: {
// devTools: true, // 是否打開調(diào)試工具,打開調(diào)試則最好調(diào)整窗口的大小
nodeIntegration: true,
contextIsolation: false,
}
})
// 通過(guò)獲取用戶屏幕的寬高來(lái)設(shè)置懸浮球的初始位置
const size = screen.getPrimaryDisplay().workAreaSize
ballWin.setPosition(size.width - 150, size.height - 200) // 設(shè)置懸浮球位置
if (process.env.WEBPACK_DEV_SERVER_URL) {
await ballWin.loadURL(`${process.env.WEBPACK_DEV_SERVER_URL}ball`)
// ballWin.webContents.openDevTools(); // 打開調(diào)試工具
} 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) {
// 當(dāng) ballWin 處于最頂端時(shí),將 mainWin 的置頂級(jí)別設(shè)為較低值
mainWin.setAlwaysOnTop(true, 'normal', -1);
mainWin.focus(); // 讓窗口獲得焦點(diǎn)
} else {
// 當(dāng) ballWin 失去置頂狀態(tài)時(shí),將 mainWin 的置頂級(jí)別設(shè)為較高值
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()
});
// 保存主窗口的當(dāng)前路由
ipcMain.on('route-change', (event, route) => {
mainWinRoutePath = route;
});
// 返回保存的路由信息
ipcMain.handle('get-mainWin-route', () => {
return mainWinRoutePath;
});
// 進(jìn)入 主窗口的某個(gè)頁(yè)面
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())
}
}
//創(chuàng)建主窗口
createWindow()
//創(chuàng)建球形窗口
createSBallWindow()
// 注冊(cè) 全局快捷鍵 刷新
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()
})
}
}打包問(wèn)題
electron-builder打包electron-v12.2.3-win32-x64.zip下載失敗,這種情況通常是有electron的4個(gè)包,無(wú)法下載成功,手動(dòng)下載后放入到系統(tǒng)對(duì)應(yīng)的文件夾中即可。
分別是
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.

按照錯(cuò)誤提示,是electron-v12.2.3-win32-x64.zip這個(gè)文件下載失敗,可以利用報(bào)錯(cuò)信息中的https://github.com/electron/electron/releases/download/v12.2.3/electron-v12.2.3-win32-x64.zip
這個(gè)地址進(jìn)行下載,或者到淘寶的鏡像地址里去下載,
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
通常系統(tǒng)會(huì)默認(rèn)隱藏AppData,關(guān)閉隱藏即可
下載后,將壓縮包解壓到這個(gè)目錄里:
C:\Users\你的用戶名\AppData\Local\electron\Cache

解壓后的文件

2、winCodeSign-2.6.0.7z.zip
下載后,將壓縮包解壓解壓到這個(gè)目錄里:
C:\Users\你的用戶名\AppData\Local\electron-builder\Cache\winCodeSign
注意:這里最后一層是winCodeSign,有的文章里顯示的是在Cache文件里解壓,這樣是錯(cuò)誤的

解壓后的:

3、nsis 和 nsis-resources
https://registry.npmmirror.com/binary.html?path=electron-builder-binaries/

下載后,將2個(gè)壓縮包都解壓到nsis文件價(jià)中,沒有nsis文件夾就自己創(chuàng)建一個(gè):
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月份已經(jīng)過(guò)期了,目前雖然還能使用,
但是可以觀察到,最終還是代理到了 https://registry.npmmirror.com,所以不如直接用 ** https://registry.npmmirror.com**
再次打包electron 應(yīng)該就沒有什么問(wèn)題了
到此這篇關(guān)于vue結(jié)合vue-electron創(chuàng)建應(yīng)用程序的文章就介紹到這了,更多相關(guān)vue-electron創(chuàng)建應(yīng)用程序內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- vue結(jié)合vue-electron創(chuàng)建應(yīng)用程序小結(jié)
- vue electron應(yīng)用調(diào)exe程序的實(shí)現(xiàn)步驟
- 使用Electron打包vue文件變成exe應(yīng)用程序的全過(guò)程
- 詳解如何使用vue和electron開發(fā)一個(gè)桌面應(yīng)用
- vue?+?electron應(yīng)用文件讀寫操作
- 如何用electron把vue項(xiàng)目打包為桌面應(yīng)用exe文件
- vue + Electron 制作桌面應(yīng)用的示例代碼
- Vite+Electron快速構(gòu)建VUE3桌面應(yīng)用的實(shí)現(xiàn)
- Vue3和Electron實(shí)現(xiàn)桌面端應(yīng)用詳解
相關(guān)文章
vue使用element實(shí)現(xiàn)上傳圖片和修改圖片功能
前幾天做到一個(gè)關(guān)于圖片上傳功能,下面這篇文章主要給大家介紹了關(guān)于vue使用element實(shí)現(xiàn)上傳圖片和修改圖片功能的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07
Vue使用pdfobject實(shí)現(xiàn)預(yù)覽pdf的示例詳解
PDFObject?是一個(gè)?JavaScript?庫(kù)用來(lái)在HTML中動(dòng)態(tài)嵌入?PDF?文檔。這篇文章主要為大家詳細(xì)介紹了使用pdfobject實(shí)現(xiàn)預(yù)覽pdf的功能,需要的可以了解一下2023-03-03
Vue實(shí)現(xiàn)點(diǎn)擊按鈕下載文件的操作代碼(后端Java)
最近項(xiàng)目中需要實(shí)現(xiàn)點(diǎn)擊按鈕下載文件的需求,前端用的vue后端使用的java代碼,今天通過(guò)本文給大家分享vue點(diǎn)擊按鈕下載文件的實(shí)現(xiàn)代碼,需要的朋友參考下吧2021-08-08
vue template當(dāng)中style背景設(shè)置不編譯問(wèn)題
這篇文章主要介紹了vue template當(dāng)中style背景設(shè)置不編譯問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-04-04
Vue 通過(guò)公共字段,拼接兩個(gè)對(duì)象數(shù)組的實(shí)例
今天小編就為大家分享一篇Vue 通過(guò)公共字段,拼接兩個(gè)對(duì)象數(shù)組的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-11-11
vue滾動(dòng)插件better-scroll使用詳解
這篇文章主要為大家詳細(xì)介紹了vue滾動(dòng)插件better-scroll,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-10-10
vue3響應(yīng)式原理之Ref用法及說(shuō)明
這篇文章主要介紹了vue3響應(yīng)式原理之Ref用法及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12
vue單頁(yè)面改造多頁(yè)面應(yīng)用的全過(guò)程記錄
眾所都知vue是一個(gè)單頁(yè)面應(yīng)用,下面這篇文章主要給大家介紹了關(guān)于vue單頁(yè)面改造多頁(yè)面應(yīng)用的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-05-05

