介绍
某些业务,需要获取用户登录的信息,从而帮忙用户自动完成其他的一系列的业务操作,从而简化用户操作。
根据需求:提出了两种方案,一种是开发google插件,另一种就是使用Electron。google插件的压缩包安装,居然是压死骆驼的稻草,所以Electron登场。
本篇文章不会讲解具体Electron开发,这边重点讲两个方面:一个是Electron运行机制,另一个讲解安装包的注意事项。
Electron运行机制
先看下下面的图:
主进程(Main Process): 是运行再nodejs上的集成了Chromium的运行平台。记住这个进程是在nodejs上运行的,所以没有window、alert等浏览器对象。
渲染进程(Renderer Process):是运行在Chromium中的,是渲染前端内容的。所以,这个进程是没有node的相关API和对象的,所以无法操作系统内容。
进程间通信
看下面的图:
Electron提供了两个对象【ipcMain】【ipcRenderer】,一个是主进程使用,一个是渲染进程使用。从而完成进程之间的通信。
主进程与渲染进程的桥梁
为啥要讲这个桥梁?假如,Electron加载了美团的官网,这个网站的代码不是我们能控制和接触到的,那么如何对网站上的Dom进行操作呢?这时就需要这个桥梁。这个桥梁让我们实现了对第三方网站的操作,同时又可以跟主进程进行通信。
- 指定桥梁文件
const createWindow = () => {
const win = new BrowserWindow({
width: 1024,
height: 768,
autoHideMenuBar: true,
webPreferences: {
nodeIntegration: true, // 允许在渲染进程中使用Node.js
preload: path.resolve(__dirname, './preload.js'), // 指定桥梁文件
},
})
}
记住,桥梁文件是执行在渲染进程中的,但是【nodeIntegration】配置成true,可以让桥梁程序能够使用部分的nodejs的API和对象。
- 操作第三方网站的样例代码
// 主进程告知,页面加载完成
ipcRenderer.on('page-loaded', (event, data) => {
console.log('page-loaded', data)
// 为第三方网站添加操作
if (window.location.href === 'https://xxxx.com/login') {
var inputsPhone = document.querySelectorAll('input[placeholder="手机号码"]')
console.log('load finish', inputsPhone.length)
if (inputsPhone && inputsPhone.length > 0) {
inputsPhone.forEach(function (input) {
// 为input元素添加失焦事件监听器
input.addEventListener('blur', function () {
// 在这里编写失焦时想执行的代码
localStorage.setItem('__root_action_mode', 'phone')
localStorage.setItem('__root_action_phone', input.value)
})
})
}
}
})
// 当页面加载完成时的回调函数
win.webContents.on('did-finish-load', () => {
setTimeout(() => {
win.webContents.send('page-loaded', 'finish-load')
}, 1000)
})
Electron 应用打包
使用的打包插件是【electron-builder】,样例配置如下:
{
"name": "",
"version": "1.0.0",
"description": "",
"main": "./code/main.js",
"scripts": {
"start": "electron .",
"rollup": "rollup --config rollup.config.js",
"build": "electron-builder"
},
"build": {
"appId": "com.XXX.XXXX",
"win": {
"target": [
{
"target": "nsis",
"arch": ["x64"]
}
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true
},
"files": ["code/*", "node_modules/**/*"]
},
"author": "XXXXX",
"license": "ISC",
"packageManager": "pnpm@8.6.2",
"volta": {
"node": "20.16.0"
},
"devDependencies": {
"electron": "^33.2.1",
"electron-builder": "^25.1.8",
"rollup": "^2.79.2",
"rollup-plugin-terser": "^7.0.2",
"rollup-plugin-copy": "^3.5.0"
},
"dependencies": {
"axios": "^1.7.8"
}
}
需要注意的是,需要使用【rollup】对代码进行混淆,然后,修改【"main": "./code/main.js"】的入口文件的指向。其次,【files】来配置打包执行的相关文件,排除无需打包的文件。
补充rollup打包配置
// rollup.config.js
import { terser } from 'rollup-plugin-terser'
const mainConfig = {
input: './main.js',
output: {
file: 'code/main.js',
format: 'iife',
},
plugins: [
terser({
compress: true,
mangle: true,
output: {
comments: false,
},
}),
],
}
const preloadConfig = {
input: 'preload.js',
output: {
file: 'code/preload.js',
format: 'iife',
},
plugins: [
terser({
compress: true,
mangle: true,
output: {
comments: false,
},
}),
],
}
export default [mainConfig, preloadConfig] // 导出配置数组
注意
- 执行打包命令时,需要从github上下载4~5个文件,所以,如果没有梯子,则打包过程会非常痛苦。所以,可以根据网上的教程,实现离线打包。