目录
- 项目初始化可以看官网非常详细
- 根路径创建.vscode文件夹
- 主进程和渲染进程之前的通信
- `ipcRenderer.send`和`ipcMain.on`的使用
- `ipcRenderer.invoke`和`ipcMain.handle`的使用
- 切换主题模式
- 文件拖放保存
- 消息通知
- 进度展示
- 图标闪烁
- 自定义菜单
- 自定义右键菜单
项目初始化可以看官网非常详细
快速入门
主要需要看下窗口的配置
const win = new BrowserWindow({
width: 800,
height: 600,
center: true,
// frame: false, //创建无边框窗口
// titleBarStyle: "hidden", //隐藏默认的标题栏
// 隐藏菜单
// autoHideMenuBar: true,
webPreferences: {
preload: path.join(__dirname, "preload.js"),
webviewTag: true, //允许使用<webview>标签
// offscreen: true, //离屏渲染
},
});
根路径创建.vscode文件夹
创建launch.json
文件,用来调试
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
主进程和渲染进程之前的通信
ipcRenderer.send
和ipcMain.on
的使用
-
preload.js
中引入contextBridge, ipcRenderer
进行消息注册
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("myAPI", {
setTitle: (title) => {
ipcRenderer.send("set-title", title);
},
});
-
main.js
中进行消息处理
app.on("ready", () => {
// 设置标题
ipcMain.on("set-title", handleSetTitle);
createWindow();
});
/**
* @description 设置title
*/
function handleSetTitle(event, title) {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
win.setTitle(title);
}
-
renderer.js
中触发事件,修改title
<h1>ipcRenderer.send-ipcMain.on的使用</h1>
<input id="title"></input>
<button id="set-title">修改title</button>
/**
* @description 修改窗口title
*/
const titleEl = document.getElementById("title");
const handleTitleBtn = document.getElementById("set-title");
handleTitleBtn.addEventListener("click", () => {
window.myAPI.setTitle(titleEl.value);
});
ipcRenderer.invoke
和ipcMain.handle
的使用
和send-on的区别主要在于可以双向通信
preload.js
const { contextBridge, ipcRenderer } = require("electron");
contextBridge.exposeInMainWorld("myAPI", {
openFile: () => ipcRenderer.invoke("dialog:openFile"),
});
main.js
app.on("ready", () => {
// 获取文件
ipcMain.handle("dialog:openFile", handleOpenFile);
createWindow();
});
/**
* @description 打开文件选择弹窗
*/
async function handleOpenFile() {
const { canceled, filePaths } = await dialog.showOpenDialog({});
if (!canceled) {
return filePaths[0];//返回值给invoke
}
}
renderer.js
<button type="button" id="file-btn">Open a File</button>
File path: <strong id="file-path"></strong>
/**
* @description 打开文件
*/
const handleFileBtn = document.getElementById("file-btn");
const filePath = document.getElementById("file-path");
handleFileBtn.addEventListener("click", async () => {
const path = await window.myAPI.openFile();
filePath.innerHTML = path;
});
切换主题模式
const {
dialog,
nativeTheme,
globalShortcut,
nativeImage,
} = require("electron");
app.on("ready", () => {
// 设置主题
ipcMain.handle("trigger-mode", triggerMode);
createWindow();
});
/**
* @description 设置主题
*/
function triggerMode() {
if (nativeTheme.shouldUseDarkColors) {
nativeTheme.themeSource = "light";
} else {
nativeTheme.themeSource = "dark";
}
return nativeTheme.shouldUseDarkColors;
}
文件拖放保存
- 注册事件
contextBridge.exposeInMainWorld("myAPI", {
startDrag: (fileName) => ipcRenderer.send("ondragstart", fileName),
});
- 处理事件
app.on("ready", () => {
// 文件的拖放保存
ipcMain.on("ondragstart", fileDrag);
createWindow();
});
/**
* @description 原生文件拖放
*/
function fileDrag(event, filePath) {
// 文件拖放
const iconName = path.join(__dirname, "doc.png"); //icon
event.sender.startDrag({
file: path.join(__dirname, filePath),
icon: iconName,
});
}
- 给元素添加拖拽事件
/**
* @description 原生文件的拖拽
*/
document.getElementById("drag").ondragstart = (event) => {
event.preventDefault();
window.myAPI.startDrag("test.txt");
};
- 根路径准备一个
test.txt
文件
消息通知
//main.js
app.on("ready", () => {
createWindow();
ipcMain.on("open-message", openMessage);
});
/**
* @description 打开消息
*/
function openMessage(event, message) {
const notice = new Notification({
title: "消息",
body: message,
});
notice.show();
notice.on("click", () => {
console.log("点击了通知");
});
}
进度展示
//main.js
app.on("ready", () => {
// 设置进度条
ipcMain.handle("progress", setProgress);
createWindow();
});
/**
* @description 设置进度条
*/
function setProgress(event, num) {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
if (num >= 1) {
win.setProgressBar(-1); //-1完成
return true;
} else {
win.setProgressBar(num);//num:0-1
return false;
}
}
图标闪烁
//main.js
app.on("ready", () => {
// 闪烁
ipcMain.on("flash", setFlash);
createWindow();
});
/**
* @description 设置闪烁
*/
function setFlash(event) {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
win.flashFrame(true);
}
自定义菜单
/**
* @description 添加菜单
*/
function addMenu() {
const menu = new Menu();
const submenu = new Menu();
menu.append(new MenuItem({ label: "测试", submenu }));
Menu.setApplicationMenu(menu);
submenu.append(new MenuItem({ label: "测试1" }));
}
自定义右键菜单
- 监听右键菜单
//renderer.js
/**
* @description 监听右键菜单
*/
window.addEventListener("contextmenu", async (e) => {
e.preventDefault();
const menu = [
{
label: "Run Code",
click: true,
},
{
label: "转到定义",
click: true,
},
{
type: "separator",
},
{
label: "复制",
click: true,
},
];
const clickOne = await window.myAPI.addContextMenu(menu);
console.log(clickOne);
});
- 添加菜单
//main.js
/**
* @description 添加右键菜单
*/
function addContextMenu(event, contextMenu) {
return new Promise((resolve) => {
const menuReal = contextMenu.map((item) => {
if (item.click) {
return {
...item,
click: () => {
resolve(item.label);
},
};
} else {
return item;
}
});
const menu = Menu.buildFromTemplate(menuReal);
menu.popup({
window: BrowserWindow.fromWebContents(event.sender),
});
});
}