目录
electron
- 应用广泛的桌面应用开发框架
- 本质结合了chromium和node.js
Electron流程模型
主进程
仅一个,主进程在 Node.js 环境中运行,具有 require 模块和使用所有 Node.js API 的能力
窗口管理
使用 BrowserWindow 模块创建和管理应用程序窗口
渲染器进程
每个打开的BrowserWindow 生成单独的渲染器进程(代码是须遵照网页标准的 )即:渲染器无权直接访问 require 或其他 Node.js API
Preload 脚本
包含了那些执行于渲染器进程中,且先于网页内容开始加载的代码,
在打开窗口时通过webPreferences 附加到主进程
const { BrowserWindow } = require('electron')
// ...
const win = new BrowserWindow({
webPreferences: {
preload: 'path/to/preload.js'
}
})
预加载脚本与浏览器共享同一个全局 Window 接口,所以它通过在全局 window 中暴露任意 API 来增强渲染器,
electron12之后默认开启上下文隔离,所以不能直接window.myApi=function(){},采用以下的方式:
实现:
const { contextBridge } = require('electron')
contextBridge.exposeInMainWorld('myAPI', {
desktop: true
})
在render.js中:
console.log(window.myAPI)// => { desktop: true }
预加载脚本访问的window并不是网站能访问的对象
例如:
// ❌ 错误使用,它直接暴露了一个没有任何参数过滤的高等级权限 API
contextBridge.exposeInMainWorld('myAPI', {
send: ipcRenderer.send
})
// ✅ 正确使用 暴露进程间通信相关 API 的正确方法是为每一种通信消息提供一种实现方法
contextBridge.exposeInMainWorld('myAPI', {
loadPreferences: () => ipcRenderer.invoke('load-prefs')
})
正确:
别人的笔记:
笔记
窗口配置项:配置项
内容安全策略:CSP、electron-security
进程间的通信
官网地址:链接
IPC通道
- ipcMain 是一个仅在主进程中以异步方式工作的模块,用于与渲染进程交换消息。
- ipcRenderer 是一个仅在渲染进程中以异步方式工作的模块,用于与主进程交换消息。
渲染器进程到主进程(单向)
- 主进程
main.js
const { app, BrowserWindow, ipcMain } = require('electron/main')
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
//写在loadFile之前
ipcMain.on('set-title', (event, title) => {
const webContents = event.sender
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
})
mainWindow.loadFile('index.html')
preload.js
暴露send方法给rendeder
向渲染器进程暴露一个全局的 window.electronAPI 变量
渲染器进程中使用window.electronAPI.setTitle()
函数
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
renderer.js
使用方法
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI.setTitle(title)
})
渲染器进程到主进程(双向)
ipcRenderer.invoke
与 ipcMain.handle
搭配
- main.js
ipcMain.handle
主进程通过ipcMain.handle 来接收消息
//返回值将作为一个 Promise 返回到最初的 invoke 调用
ipcMain.handle('dialog:openFile', handleFileOpen)
//dialog: 前缀对代码没有影响。 它仅用作命名空间以帮助提高代码的可读性。
- preload.js
渲染进程通过 ipcRenderer.invoke 发送消息
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
- renderer
const filePath = await window.electronAPI.openFile()
主进程到渲染器进程
将消息从主进程发送到渲染器进程时,需要指定是哪一个渲染器接收消息
使用WebContents
- main.js
通过mainWindow.webContents.send发送消息和参数
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
const menu = Menu.buildFromTemplate([
{
label: app.name,
submenu: [
{
click: () => mainWindow.webContents.send('update-counter', 1),
label: 'Increment'
},
{
click: () => mainWindow.webContents.send('update-counter', -1),
label: 'Decrement'
}
]
}
])
- preload.js
ipcRenderer.on接收
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
onUpdateCounter: (callback) => ipcRenderer.on('update-counter', (_event, value) => callback(value))
})
- renderer.js
window.electronAPI.onUpdateCounter(()=>{})
webview
electron与webview的通信
在窗口中webview引入其他网页,以节省开发成本,会再注入一些js、css来对这个页面进行改动,其中就有添加事件,webview所在窗口需要得知事件触发。
<template>
<div class ="container">
<webview
id="webview"
ref="webview"
:src="webviewSrc"
disablewebsecurity
class="webview"
nodeintegration
/>
</div>
</template>
webview页面使用ipcRenderer
向窗口发送信息
ipcRenderer.sendToHost()
let ipcRenderer = require('electron').ipcRenderer
var paramsJSON = {}
ipcRenderer && ipcRenderer.sendToHost(paramsJSON)
webview所在页面监听接收信息
webview.addEventListener('ipc-message', (event) => {
if (event.channel) {
let params = JSON.parse(event.channel)
}
})