更新依赖
npm install --registry=https://registry.npm.taobao.org
手动明跳转路由
location.hash = '#/chat'
手动获取当前路由
window.location.href
electron常用配置
"build": {
"productName":"xxxx",//项目名 这也是生成的exe文件的前缀名
"appId": "com.leon.xxxxx",//包名
"copyright":"xxxx",//版权 信息
"directories": { // 输出文件夹
"output": "build"
},
"nsis": {
"oneClick": false, // 是否一键安装
"allowElevation": true, // 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
"allowToChangeInstallationDirectory": true, // 允许修改安装目录
"installerIcon": "./build/icons/aaa.ico",// 安装图标
"uninstallerIcon": "./build/icons/bbb.ico",//卸载图标
"installerHeaderIcon": "./build/icons/aaa.ico", // 安装时头部图标
"createDesktopShortcut": true, // 创建桌面图标
"createStartMenuShortcut": true,// 创建开始菜单图标
"shortcutName": "xxxx", // 图标名称
"include": "build/script/installer.nsh", // 包含的自定义nsis脚本
},
"publish": [
{
"provider": "generic", // 服务器提供商 也可以是GitHub等等
"url": "http://xxxxx/" // 服务器地址
}
],
"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/aims.ico",
"target": [
{
"target": "nsis",
"arch": [
'x64',// 64位
'ia32' // 32位
]
}
]
},
"linux": {
"icon": "build/icons"
}
}
安装包打入向导
- 下载(使用此方法,代码打包时关闭nsis配置)
- NSIS中文版下载地址:https://pan.baidu.com/s/1mitSQU0
官方说使用asar pack ./index.html app.asar --unpack *.node 得到app.asar可以防止杀毒软件的注意,但是我用过之后并没有效果,都躲不过360的注意,但是不影响流程,如果有人解决了360误报的问题,希望可以告诉我,谢谢 ^_^
vue.config.js配置
pluginOptions: {
electronBuilder: {
nodeIntegration: true,
builderOptions: {
asar: false, // 是否把app文件夹压缩成app.asar
win: {
icon: './public/app.ico',
target: [
{
target: 'nsis', // 利用nsis制作安装程序
arch: [
// 'x64', // 64位
'ia32' // 32位
]
}
]
},
nsis: {
oneClick: false, // 是否一键安装
// 允许请求提升。 如果为false,则用户必须使用提升的权限重新启动安装程序。
allowElevation: true,
perMachine: false,
allowToChangeInstallationDirectory: true, // 允许修改安装目录
installerIcon: './public/app.ico', // 安装图标
uninstallerIcon: './public/app.ico', // 卸载图标
installerHeaderIcon: './public/app.ico', // 安装时头部图标
createDesktopShortcut: true, // 创建桌面图标
createStartMenuShortcut: true, // 创建开始菜单图标
shortcutName: name // 图标名称
},
mac: {
icon: './public/app.ico'
},
publish: [
{
provider: 'generic',
url: 'http://xxxx/' // 版本服务器地址
}
],
productName: 'YueGongJia', // 包名
appId: 'com.gongyoushijie.ttgy.electron-vue', // 项目id
copyright: '最终解释权归长时科技所有', // 版权信息
files: ['./**/*'],
directories: {
output: './dists' // 输出文件路径
}
}
}
}
electron配置(package.json)
"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",
electron配置(background.js)
'use strict'
'use strict'
import { app, protocol, BrowserWindow, globalShortcut, Menu, ipcMain } from 'electron'
import { createProtocol } from 'vue-cli-plugin-electron-builder/lib'
const isDevelopment = process.env.NODE_ENV !== 'production'
// Scheme must be registered before the app is ready
protocol.registerSchemesAsPrivileged([
{
scheme: 'app',
privileges: {
secure: true,
standard: true
}
}
])
let win = null
// let loadingWindow = null
// function createLoadingWindow() { // 加载页面窗口
// loadingWindow = new BrowserWindow({
// height: 200,
// useContentSize: true,
// width: 200,
// show: true,
// transparent: true,
// backgroundColor: '#000',
// maximizable: false, // 禁止双击放大
// frame: false // 去掉顶部操作栏
// })
// // eslint-disable-next-line no-undef
// const loadingURL = `${__static}/loading.html`
// loadingWindow.loadURL(loadingURL)
// Menu.setApplicationMenu(null)
// loadingWindow.on('closed', () => {
// loadingWindow = null
// })
// }
async function createWindow() {
// 创建浏览器窗口
win = new BrowserWindow({
width: 800,
height: 600,
show: false,
backgroundColor: '#000',
opacity: 0,
webPreferences: {
webSecurity: false,
// Use pluginOptions.nodeIntegration, leave this alone
// See nklayman.github.io/vue-cli-plugin-electron-builder/guide/security.html#node-integration for more info
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION
},
// eslint-disable-next-line no-undef
icon: `${__static}/app.ico`
})
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')
// 不在开发中时加载index.html
win.loadURL('app://./index.html')
}
if (!isDevelopment) {
createMenu()
}
win.maximize()
win.on('ready-to-show', () => {
win.setOpacity(1.0)
})
// mainWindow要关闭时的方法↓
win.on('close', e => {
e.preventDefault() // 先阻止一下默认行为,不然直接关了,提示框只会闪一下
win.webContents.send('appClose')
ipcMain.on('appClose', () => {
win = null
app.exit()
})
})
win.on('closed', () => {
win = null
})
}
// 设置菜单栏
function createMenu() {
// darwin表示macOS,针对macOS的设置
if (process.platform === 'darwin') {
const template = [
{
label: 'App Demo',
submenu: [
{
role: 'about'
},
{
role: 'quit'
}
]
}
]
const menu = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(menu)
} else {
// windows及linux系统
Menu.setApplicationMenu(null)
}
}
// close httpcache
app.commandLine.appendSwitch('--disable-http-cache')
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
// eslint-disable-next-line space-before-function-paren
app.on('ready', async () => {
// createLoadingWindow()
createWindow()
ipcMain.on('close-loading-window', (e, res) => {
if (res.isClose) {
// if (loadingWindow) loadingWindow.close()
win.show()
}
})
if (isDevelopment && !process.env.IS_TEST) {
// eslint-disable-next-line space-before-function-paren
globalShortcut.register('F10', function() {
win.webContents.openDevTools()
})
}
})
app.on('activate', () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
// 关闭所有窗口后退出。
app.on('window-all-closed', () => {
// 在macOS上,应用程序及其菜单栏很常见
// 保持活动状态,直到用户使用Cmd + Q明确退出为止
if (process.platform !== 'darwin') {
app.quit()
}
})
// Exit cleanly on request from parent process in development mode.
if (isDevelopment && !process.env.IS_TEST) {
if (process.platform === 'win32') {
process.on('message', data => {
if (data === 'graceful-exit') {
app.quit()
}
})
} else {
process.on('SIGTERM', () => {
app.quit()
})
}
}
// 自动更新
import { autoUpdater } from 'electron-updater'
ipcMain.on('update', () => {
if (isDevelopment) {
return
}
updateHandle()
})
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle() {
const message = {
error: '检查更新出错',
checking: '检查更新中……',
updateAva: '更新可用',
updateNotAva: '现在已是最新版本'
}
// 如下应用程序的路径请自行替换成自己应用程序的路径
const updateFeedUrl = 'http://xxxx/'
// if (process.platform === 'darwin') {
// updateFeedUrl = 'http://xxxx//'
// }
autoUpdater.setFeedURL(updateFeedUrl)
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('error', function() {
sendUpdateMessage(message.error)
})
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('checking-for-update', function() {
sendUpdateMessage(message.checking)
})
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('update-available', function() {})
// 没有可用更新的时候触发。
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('update-not-available', function() {
sendUpdateMessage(message.updateNotAva)
})
// 更新下载进度事件
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('download-progress', function(progressObj) {
win.webContents.send('downloadProgress', progressObj)
win.setProgressBar(progressObj.percent / 100)
})
// eslint-disable-next-line space-before-function-paren
autoUpdater.on('update-downloaded', function() {
sendUpdateMessage('UpdataNow')
ipcMain.on('isUpdataNow', () => {
// 退出并安装更新包
autoUpdater.quitAndInstall()
})
})
// })
// 执行自动更新检查
autoUpdater.checkForUpdates()
}
// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage(text) {
win.webContents.send('updateMessage', text)
}
自动更新的app.vue
<template>
<div id="app">
<router-view />
<div v-if="upDateStatus" class="upDate">
<el-progress :text-inside="true" :percentage="percent" :stroke-linecap="'butt'" :stroke-width="20" :format="format" show-text color="#00d8ff" />
</div>
</div>
</template>
<script>
import { ipcRenderer } from 'electron'
export default {
name: 'App',
data() {
return {
percent: 0,
upDateStatus: false
}
},
beforeMount() {
ipcRenderer.send('close-loading-window', {
isClose: true
})
},
mounted() {
const _this = this
/** 发起更新*/
ipcRenderer.send('update')
/** 监听下载进度*/
ipcRenderer.on('downloadProgress', (e, data) => {
if (!_this.upDate) {
_this.upDateStatus = true
}
_this.percent = Number(data.percent).toFixed(2)
console.log(data.percent)
})
/** 安装包下载完时提示*/
ipcRenderer.on('updateMessage', (e, data) => {
if (data === 'UpdataNow') {
_this.upDateStatus = false
this.$confirm('发现新版本,是否现在更新?', '提示', {
confirmButtonText: '更新',
cancelButtonText: '取消',
cancelButtonClass: 'cancelButtonClass',
confirmButtonClass: 'confirmButtonClass'
}).then(() => {
ipcRenderer.send('isUpdataNow')
})
}
})
/** 下载时关闭程序提示*/
ipcRenderer.on('appClose', () => {
if (_this.upDateStatus) {
this.$confirm(`应用更新中(${_this.percent}%),退出后将要重新更新?`, '提示', {
confirmButtonText: '退出',
cancelButtonText: '取消',
cancelButtonClass: 'cancelButtonClass',
confirmButtonClass: 'confirmButtonClass'
}).then(() => {
ipcRenderer.send('appClose')
})
} else {
ipcRenderer.send('appClose')
}
})
},
methods: {
format(percentage) {
return percentage === 100 ? '下载完成,请重启' : `下载进度${percentage}%,请勿关闭`
}
}
}
// 阻止拖拽文件的默认事件
document.addEventListener(
'dragover',
// eslint-disable-next-line space-before-function-paren
function (e) {
// console.log(e)
e.preventDefault()
},
false
)
document.addEventListener(
'drop',
// eslint-disable-next-line space-before-function-paren
function (e) {
// console.log(e)
e.preventDefault()
},
false
)
// rem 自适应
// eslint-disable-next-line space-before-function-paren
;(function () {
const html = document.documentElement
// 设置默认主题
const body = document.querySelector('body')
body.setAttribute('data-theme', 'default')
function setFont() {
const cliWidth = html.clientWidth
html.style.fontSize = 16 * (cliWidth / 1920) + 'px'
}
setFont()
// eslint-disable-next-line space-before-function-paren
window.onresize = function () {
setFont()
}
})()
</script>
<style lang="scss">
@import './styles/index.scss'; // 全局自定义的css样式
</style>
<style lang="scss" scoped>
.upDate {
position: fixed;
top: 0;
left: 0;
width: 100%;
opacity: 0.5;
}
::v-deep .el-progress-bar__outer,
::v-deep .el-progress-bar__inner {
border-radius: 0 !important;
}
::v-deep .el-progress-bar__innerText {
color: #000 !important;
font-weight: bold;
}
</style>