一、前言
-
NW.js
和Electron
都可以用前端的知识来开发桌面应用。NW.js
和Electron
起初是同一 个作者开发。后来种种原因分为两个产品。一个命名为NW.js
(英特尔公司提供技术支持)、 另一命名为Electron(Github
公司提供技术支持)。 -
NW.js
和Electron
可以用Nodejs
中几乎所有的模块NW.js
和Electron
不仅可以把html
写的web
页面打包成跨平台可以安装到电脑上面的软件,也可以通过javascript
访问操作 系统原生的 UI 和 Api(控制窗口、添加菜单项目、托盘应用菜单、读写文件、访问剪贴板)。
1.1 Electron 是由谁开发的?
Electron 是由 Github 开发
1.2 Electron 是什么?
Electron 是一个用 HTML,CSS 和 JavaScript 来构建跨平台桌面应用程序的一个开源库
1.3 Electron 把 HTML,CSS 和 JavaScript 组合的程序构建为跨平台桌面应用程序的原理 是什么?
原理为 Electron 通过将 Chromium 和 Node.js 合并到同一个运行时环境中,并将其打包为 Mac,Windows 和 Linux 系统下的应用来实现这一目的。
二、electron-vue
作为前端,本身需要学的东西就很多。所以这里直接使用 electron-vue
来构建桌面应用。
electron-vue 环境搭建、创建项目
这里推荐yarn
,至于为什么,官网是这么推荐的。而且在安装依赖时,速度也是很快
vue init simulatedgreg/electron-vue my-project
cd my-project
yarn
yarn run dev
electron-vue 中隐藏顶部菜单隐藏
electron-vue 中隐藏顶部菜单隐藏顶部最大化、最小化、关闭按钮 自定最大化、最小化 、关闭按钮
electron-vue 中隐藏顶部菜单
// src/main/index.js
mainWindow.setMenu(null)
electron-vue 中隐藏关闭 最大化 最小化按钮
// src/main/index.js
mainWindow = new BrowserWindow({
height: 620,
useContentSize: true,
width: 1280,
frame: false /*去掉顶部导航 去掉关闭按钮 最大化最小化按钮*/
})
electron-vue 自定义关闭/最大化最小化按钮
// 注意在mac下不需要监听窗口最大最小化、以为系统默认支持,这个只是针对windows平台
ipc.on('window-min',function() {
mainWindow.minimize();
})
//登录窗口最大化
ipc.on('window-max',function(){
if (mainWindow.isMaximized()) {
mainWindow.restore();
} else {
mainWindow.maximize();
}
})
ipc.on('window-close',function() {
mainWindow.close();
})
electron-vue 自定义导航可拖拽
- 可拖拽的 css: -webkit-app-region: drag;
- 不可拖拽的 css: -webkit-app-region: no-drag;
electron-update 实现手动/自动更新
话不多说,直接上代码。。。
// package.json
"build": {
...
"publish": {
"provider": "generic", // 这个意思是,使用自己的文件服务器
"url": "http:..." // 文件服务器的地址
}
...
}
文件服务器的构建,根据自己的实际情况使用技术栈。
我是使用nginx
搭建了一个文件服务器,具体代码就不贴出来了,比较简单
// src/main/index.js
'use strict'
import { app, BrowserWindow, ipcMain, globalShortcut } from 'electron'
import { autoUpdater } from 'electron-updater'
const uploadUrl = '文件服务器地址'
/*
* Set `__static` path to static files in production
* https://simulatedgreg.gitbooks.io/electron-vue/content/en/using-static-assets.html
*/
if (process.env.NODE_ENV !== 'development') {
global.__static = require('path').join(__dirname, '/static').replace(/\\/g, '\\\\')
}
let mainWindow
const winURL = process.env.NODE_ENV === 'development'
? `http://localhost:9080`
: `file://${__dirname}/index.html`
// 检测更新,在你想要检查更新的时候执行,renderer事件触发后的操作自行编写
function updateHandle () {
let message = {
error: { status: -1, message: '检查更新出错' },
checking: { status: 1, message: '正在检查更新……' },
updateAva: { status: 2, message: '检测到新版本,正在下载……' },
updateNotAva: { status: 3, message: '已是最新版本,无需更新' }
}
// const os = require('os')
autoUpdater.setFeedURL(uploadUrl)
autoUpdater.on('error', function () {
sendUpdateMessage(message.error)
})
autoUpdater.on('checking-for-update', function () {
sendUpdateMessage(message.checking)
})
autoUpdater.on('update-available', function (info) {
sendUpdateMessage(message.updateAva)
})
autoUpdater.on('update-not-available', function (info) {
sendUpdateMessage(message.updateNotAva)
})
// 更新下载进度事件
autoUpdater.on('download-progress', function (progressObj) {
mainWindow.webContents.send('downloadProgress', progressObj)
})
autoUpdater.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
// ipcMain.on('isUpdateNow', (e, arg) => {
// console.log(arguments)
// console.log('开始更新')
// some code here to handle event
autoUpdater.quitAndInstall()
// })
// mainWindow.webContents.send('isUpdateNow')
})
autoUpdater.checkForUpdates()
}
ipcMain.on('checkForUpdate', () => {
updateHandle()
// 执行自动更新检查
})
// 通过main进程发送事件给renderer进程,提示更新信息
function sendUpdateMessage (text) {
mainWindow.webContents.send('message', text)
}
function createWindow () {
/**
* Initial window options
*/
mainWindow = new BrowserWindow({
height: 363,
useContentSize: true,
width: 600
})
mainWindow.loadURL(winURL)
// let update = new Update(mainWindow)
mainWindow.on('closed', () => {
mainWindow = null
})
mainWindow.setMenu(null)
// updateHandle()
// 调试
globalShortcut.register('CTRL+SHIFT+I', function () {
mainWindow.webContents.openDevTools()
})
}
app.on('ready', async () => {
createWindow()
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', () => {
if (mainWindow === null) {
createWindow()
}
})
视图层
这里使用了element-ui
,根据自己的情况选取ui
框架
// components/update
<template>
<div class="com-update">
<el-row type="flex" justify="end">
<el-col :span="1" :xs="3" :md="2" :lg="1">
<el-tag @click="showUpdater" size="mini" type="info" effect="plain">检查版本</el-tag>
</el-col>
</el-row>
<el-dialog
title="更新中,请稍等。。。"
:visible="showDialog"
width="30%"
center
:close-on-press-escape="false"
:close-on-click-modal="false"
:show-close="false"
>
<el-row type="flex" justify="center">
<el-col :span="11">
<el-progress type="circle" :percentage="process"></el-progress>
</el-col>
</el-row>
</el-dialog>
</div>
</template>
<script>
import { ipcRenderer } from 'electron'
export default {
name: 'update',
data() {
return {
loading: '',
status: null,
message: '',
showDialog: false,
process: 0
}
},
watch: {
status() {
let status = this.status
if (status === -1) {
this.$message({
type: 'error',
center: true,
message: `${this.message}`
})
} else if (status === 1) {
this.$message.closeAll()
this.$message({
type: 'info',
center: true,
message: `${this.message}`,
iconClass: 'el-icon-loading'
})
} else if (status === 2) {
this.showDialog = true
this.$message.closeAll()
this.$message({
type: 'success',
center: true,
message: `${this.message}`,
iconClass: 'el-icon-loading'
})
} else if (status === 3) {
this.$message.closeAll()
this.$message({
type: 'success',
center: true,
message: `${this.message}`
})
}
if (status !== 2) {
this.showDialog = false
}
}
},
methods: {
showUpdater() {
this.showUpdate = true
ipcRenderer.send('checkForUpdate')
}
},
mounted() {
ipcRenderer.on('message', (event, obj) => {
console.log('obj', obj)
this.status = obj.status
this.message = obj.message
})
// 注意:“downloadProgress”事件可能存在无法触发的问题,只需要限制一下下载网速就好了
ipcRenderer.on('downloadProgress', (event, progressObj) => {
console.log('progressObj', progressObj)
console.log('progressObj.percent', progressObj.percent)
this.process = progressObj.percent || 0
if (this.process === 100) {
this.showDialog = false
}
})
// ipcRenderer.on('isUpdateNow', () => {
// ipcRenderer.send('isUpdateNow')
// })
},
destroyed() {
ipcRenderer.removeAllListeners(['message', 'downloadProgress', 'isUpdateNow'])
}
}
</script>
持续更新中。。。
分享不易,喜欢的话一定别忘了点💖!!!
只关注不点💖的都是耍流氓,只收藏也不点💖的也一样是耍流氓。
结束👍👍👍。