构建Vite-electron项目
npm i electron-vite -D
npm create @quick-start/electron project-name -- template vue-ts
Electron的运行流程
Electron进程
一、主进程:有且唯一的应用程序入口点,在 Node.js 环境中运行,具有 require
模块和使用所有 Node.js API 的能力。
二、渲染进程:每个打开的 BrowserWindow
( 与每个网页嵌入 )都会生成一个单独的渲染器进程,无权直接访问 require
或其他 Node.js API,入口为HTML文件
三、预加载脚本:包含执行于渲染器进程中,且先于网页内容开始加载的代码 。 运行在渲染进程的环境中,却有使用Node.js API的能力,在BrowserWindow
构造方法中的 webPreferences
选项里被附加到主进程。
ps:由于预加载脚本与渲染进程的运行环境是隔离开,如果想要在预加载脚本中暴露信息则使用``contextBridge`模块实现,但也有暴露限制例如暴露原型或者 Symbol。不可直接暴露权限API,可采取暴露API功能实现方法。
Electron的模块
app模块:控制应用程序的生命周期
BrowserWindow模块:窗口管理,每个实例对应一个窗口,且在单独的渲染器进程中加载一个网页。当实例被销毁时,与其相应的渲染器进程也会被终止
autoUpdater模块:程序自动更新,window和mac支持
BrowserView模块:创建和控制视图,相对于父窗口的子窗口,窗口里面开窗口
clipboard模块:在系统剪贴板上执行复制和粘贴操作
dialog模块:显示用于打开和保存文件、警报等的本机系统对话框
Menu模块:创建原生应用菜单和上下文菜单
powerMonitor模块:监听电源状态变化
powerSaveBlocker模块:阻止系统进入低功耗 (休眠) 模式
screen模块:检索有关屏幕大小、显示器、光标位置等的信息
safeStorage 模块:允许访问简单的加密和解密字符串,以便存储在本地机器上
session模块:管理浏览器会话、cookie、缓存、代理设置等
protocol模块:注册自定义协议并拦截基于现有协议的请求
pushNotifications模块:注册并接收远程推送通知服务的通知
shell模块:使网页在本地浏览器打开而不是在窗口中,新窗口直接window.open(url)
即可
systemPreferences模块:获取系统偏好
Tray模块:添加图标和上下文菜单到系统通知区
globalShortcut模块:全局快捷键
const globalShortcut = electron.globalShortcut; //引入
//const globalShortcut = require('global-shortcut');
//!必须在ready监听回调中使用
app.on("ready", () => {
globalShortcut.register("ctrl+x", () => {
//使用快捷键的回调
});
let judgeRegister = globalShortcut.isRegister('ctrl+e')?'注册成功':'注册失败' //判断快捷键是否注册成功
});
app.on('will-quit', ()=> {
globalShortcut.unregister('ctrl+x'); //注销ctrl+x快捷键
globalShortcut.unregisterAll(); //注销全部快捷键
});
contextBridge模块:在隔离的上下文中创建一个安全的、双向的、同步的桥梁
nativeImage模块:使用 PNG 或 JPG 文件创建托盘、dock和应用程序图标
webFrame模块:自定义渲染当前网页
ipc模块:进程通信,负责进程之间的事件触发,数据传递
1、渲染进程单向通信主进程 // 修改程序名称
// index.html
<html>
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Hello World!</title>
</head>
<body>
Title: <input id="title"/>
<button id="btn" type="button">Set</button>
<script src="./renderer.js"></script>
</body>
</html>
// main.ts
const {app, BrowserWindow, ipcMain} = require('electron')
const path = require('path')
function handleSetTitle (event, title) {
// event是消息发送方,
const webContents = event.sender
// 确定是哪个渲染进程调用,然后作用与该渲染进程
const win = BrowserWindow.fromWebContents(webContents)
win.setTitle(title)
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
ipcMain.on('set-title', handleSetTitle)
createWindow()
}
// preload.ts
const { contextBridge, ipcRenderer } = require('electron')
// 通过contextBridge安全的向渲染进程暴露一个electronAPI对象,其中是渲染进程所需实现业务的方法,不可直接暴露Api给渲染
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
... // 更多方法
})
// render.ts
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
// 点击触发proload提供的winndow.electronAPI对象中的setTitle方法
window.electronAPI.setTitle(title)
});
2、主进程渲染进程双向通信 // 渲染进程调用主进程的原生文件对话框
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Dialog</title>
</head>
<body>
<button type="button" id="btn">Open a File</button>
File path: <strong id="filePath"></strong>
<script src='./renderer.js'></script>
</body>
</html>
// render.ts
const btn = document.getElementById('btn')
const filePathElement = document.getElementById('filePath')
btn.addEventListener('click', async () => {
// 触发由contentBrige模块暴露的window.electronAPI对象openFile方法
const filePath = await window.electronAPI.openFile()
filePathElement.innerText = filePath
})
// preload.ts
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI',{
// 双向通信触发通过invoke方法
openFile: () => ipcRenderer.invoke('dialog:openFile')
})
// main.ts
const {app, BrowserWindow, ipcMain, dialog} = require('electron')
const path = require('path')
async function handleFileOpen() {
const { canceled, filePaths } = await dialog.showOpenDialog()
if (canceled) {
return
} else {
return filePaths[0]
}
}
function createWindow () {
const mainWindow = new BrowserWindow({
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})
mainWindow.loadFile('index.html')
}
app.whenReady().then(() => {
// 双向通信接收通过handle方法
ipcMain.handle('dialog:openFile', handleFileOpen)
createWindow()
app.on('activate', function () {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit()
})
3、主进程通信渲染进程
// index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
<title>Menu Counter</title>
</head>
<body>
Current value: <strong id="counter">0</strong>
<script src="./renderer.js"></script>
</body>
</html>
// render.ts
const counter = document.getElementById('counter')
window.electronAPI.handleCounter((event, value) => {
const oldValue = Number(counter.innerText)
const newValue = oldValue + value
counter.innerText = newValue
// 回复??
event.sender.send('counter-value', newValue)
})
// preload.ts
const { contextBridge, ipcRenderer } = require('electron')
contextBridge.exposeInMainWorld('electronAPI', {
handleCounter: (callback) => ipcRenderer.on('update-counter', callback)
})
// main.ts
const {app, BrowserWindow, Menu, ipcMain} = require('electron')
const path = require('path')
function createWindow () {
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',
}
]
}
])
Menu.setApplicationMenu(menu)
mainWindow.loadFile('index.html')
}
app.whenReady(()=>{
// 接收渲染进程回复的
ipcMain.on('counter-value', (_event, value) => {
console.log(value)
})
})
//...
4、渲染进程通信渲染进程
一般很少用,因为渲染进程用框架例如Vue有N种通信方式
1、把主进程当作事件总线来用
2、主进程将一个MessagePort传递到两个渲染器。 这将允许在初始设置后渲染器之间直接进行通信。
设置网络是否连接的不同回调
window.addEventListener("online", () => {}); //上网
window.addEventListener("offline", () => {}); //断网
标签:const,渲染,app,Electron,模块,进程,识别,require,Vite
From: https://www.cnblogs.com/kq981024/p/16996820.html