Electron 入门
本文章的 electron 版本:19.0.3
学习体会:
- electron 更新非常快,一切以官方文档优先
- 一定多敲代码而不是看看,因为 electron 坑挺多的。提前遇坑,未来的开发体验会更顺畅
1. electron 安装
yarn init -y # 包管理初始化
yarn add electron # 下载 electron
下载完后通过 npx electron -v
查看是否下载成功。如果下载成功了会返回版本号。
此时在根目录中执行以下命令:./node_modules/.bin/electron
electron 会开启一个默认界面
2. hello world
在一个 HTML 文件里写一个最简单的 hello world。首先创建一个 main.js ,这是主进程,用于启动加载页面。当 app ready 状态的时候,触发事件,此时创建一个 BrowserWindow 实例,并在这个窗口内加载页面。
// 引入 app 和窗口引用
const { app, BrowserWindow } = require("electron");
// 创建窗口函数
const createWindow = () => {
const win = new BrowserWindow({
width: 300,
height: 300,
});
win.loadFile("index.html");
};
// 监控主进程,准备好后启动窗口
app.whenReady().then(() => {
createWindow();
});
写完后执行命令 ./node_modules/.bin/electron .
,或者为了以后方便,写在 package.json 里的 scripts,然后 yarn start
:
"scripts": {
"start": "./node_modules/.bin/electron ."
}
可以看到 app 被成功加载出来。
关闭进程是好习惯,关闭窗口后,根据操作系统类别来判断是否完全退出。
Linux 和 Windows 系统如果关闭了所有窗口,便是完全退出了 App,macOS 需要 docker 栏下方的白色点消失才代表退出 App,窗口关闭了并不代表 App 完全退出。
因此 macOS 和非 macOS 的退出判断逻辑得翻开。以下是 main.js 所有代码,包括了退出的逻辑:
// 引入 app 和窗口引用
const { app, BrowserWindow } = require("electron");
// 创建窗口函数
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
});
// 加载 index.html,启动渲染进程
win.loadFile("index.html");
// 打开开发工具
// mainWindow.webContents.openDevTools()
};
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
// In this file you can include the rest of your app's specific main process
// code. 也可以拆分成几个文件,然后用 require 导入。
3. electron 应用获取本地资源
electron 可以集成 node 的功能。现在要实现一个功能,点击 App 上的按钮,来获取到本地文件上的信息并输出。
修改 main.js 里的配置项
首先,开启窗口的 window 配置里面配置一个属性,webPreferences,配置自定义选项。
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 集成 node
nodeIntegration: true,
// 关闭上下文隔离,兼容 require 引入
contextIsolation: false,
},
});
nodeIntegration: true
表示页面具有 node 继承,并且可以使用 node API 去访问低层系统资源,这样就可以读取本地资源了。
后边 node 里边会用到 require 语句,配置 contextIsolation: false
即可。
页面 index 写法
常规的原生写法,后面测试效果用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hello world</title>
</head>
<body>
<button id="btn">点击获取运动列表</button>
<div id="sports"></div>
<script src="./render/index.js"></script>
</body>
</html>
render/index.js 写法
里面写了点击按钮事件触发后,读取 txt 文件并填充 div 内容的逻辑。
const fs = require("fs");
const path = require("path");
window.onload = function () {
const btn = document.querySelector("#btn");
const sports = document.querySelector("#sports");
btn.addEventListener("click", function () {
const filePath = path.resolve(__dirname, "sport.txt");
fs.readFile(filePath, (err, data) => {
sports.innerHTML = data;
});
});
};
4. remote
remote 帮助在渲染进程中调用主进程里使用的方法和对象。
举个例子,想要有个功能,希望点击应用的其中一个按钮后,启动一个新应用窗口。实现效果如下图:
因为窗口页面是渲染进程,启动新应用窗口需要用到主进程。因此要实现这个功能的话,就需要用到 remote。
安装 remote 相关包:
yarn add @electron/remote
4.1 主进程支持 remote
主进程代码:
// 引入 app 和窗口引用
const { app, BrowserWindow } = require("electron");
// 初始化 remote
require("@electron/remote/main").initialize();
// 创建窗口函数
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 集成 node
nodeIntegration: true,
// 关闭上下文隔离,兼容 require 引入
contextIsolation: false,
},
});
// 加载 index.html
win.loadFile("demo.html");
// 打开开发工具
// mainWindow.webContents.openDevTools()
};
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow();
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 开启 remote
app.on("browser-window-created", (_, window) => {
require("@electron/remote/main").enable(window.webContents);
});
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
// In this file you can include the rest of your app's specific main process
// code. 也可以拆分成几个文件,然后用 require 导入。
这里有两个重要的细节:
-
remote 需要初始化
// 初始化 remote require("@electron/remote/main").initialize();
-
app 开启 remote 的支持
// 开启 remote app.on("browser-window-created", (_, window) => { require("@electron/remote/main").enable(window.webContents); });
4.2 写加载的 HTML 页面
这个 demo 加载的是 demo.html 页面,代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="btn">打开新的窗口</button>
<script src="render/demo.js"></script>
</body>
</html>
有个按钮,期望点击它会产生一个新窗口。同时加载 demo.js 文件。
4.3 渲染进程调用主进程方法
在 demo.js 中,代码如下:
const { BrowserWindow } = require("@electron/remote");
const btn = document.querySelector("#btn");
const createWindow = () => {
const win = new BrowserWindow({
width: 500,
height: 500,
});
win.loadFile("newPage.html");
};
window.onload = function () {
btn.addEventListener("click", createWindow);
};
看起来和主进程的代码差别不是很大,在点击的时候,创建一个新的页面。其中,引用的 BrowserWindow 来自于 @electron/remote
。
5. electron 菜单栏的创建和绑定事件
新建一个文件,menu.js,用于写菜单栏,然后放到主进程里。
5.1 写菜单栏样式
用什么数据结构能准确地表示菜单栏?如果自己设计的话,肯定会想到数组,数组内存放着每个菜单选项,然后菜单选项是一个对象,里面存储菜单选项的相关信息。
官网上有写菜单栏的示范案例:
const { app, Menu } = require("electron");
const isMac = process.platform === "darwin";
const template = [
// { role: 'appMenu' }
...(isMac
? [
{
label: app.name,
submenu: [
{ role: "about", label: "关于" },
{ type: "separator" },
{ role: "services" },
{ type: "separator" },
{ role: "hide" },
{ role: "hideOthers" },
{ role: "unhide" },
{ type: "separator" },
{ role: "quit" },
],
},
]
: []),
// { role: 'fileMenu' }
{
label: "File",
submenu: [isMac ? { role: "close" } : { role: "quit" }],
},
// { role: 'editMenu' }
{
label: "Edit",
submenu: [
{ role: "undo" },
{ role: "redo" },
{ type: "separator" },
{ role: "cut" },
{ role: "copy" },
{ role: "paste" },
...(isMac
? [
{ role: "pasteAndMatchStyle" },
{ role: "delete" },
{ role: "selectAll" },
{ type: "separator" },
{
label: "Speech",
submenu: [{ role: "startSpeaking" }, { role: "stopSpeaking" }],
},
]
: [{ role: "delete" }, { type: "separator" }, { role: "selectAll" }]),
],
},
// { role: 'viewMenu' }
{
label: "View",
submenu: [
{ role: "reload" },
{ role: "forceReload" },
{ role: "toggleDevTools" },
{ type: "separator" },
{ role: "resetZoom" },
{ role: "zoomIn" },
{ role: "zoomOut" },
{ type: "separator" },
{ role: "togglefullscreen" },
],
},
// { role: 'windowMenu' }
{
label: "Window",
submenu: [
{ role: "minimize" },
{ role: "zoom" },
...(isMac
? [
{ type: "separator" },
{ role: "front" },
{ type: "separator" },
{ role: "window" },
]
: [{ role: "close" }]),
],
},
{
role: "help",
submenu: [
{
label: "Learn More",
click: async () => {
const { shell } = require("electron");
await shell.openExternal("https://electronjs.org");
},
},
],
},
];
const menu = Menu.buildFromTemplate(template);
module.exports = {
menu
};
上面的 template 变量是存储菜单栏格式的数据结构。里面的基本信息有:
-
role:职责,内置了常用的功能,不用自己写菜单点击后的效果
-
label:菜单栏显示文字。如果没有 label,则使用 role 配置的显示文字
-
submenu:存放子菜单
-
type: "separator"
:分隔符 -
click:点击菜单选项后发生的事件
例如点击后想跳出一个新窗口,代码这样写:
click: () => { let win = new BrowserWindow({ width: 500, height: 500, }); win.loadFile("newPage.html"); win.on("closed", () => { win = null }); };
官方示例里:
{ label: "Learn More", click: async () => { const { shell } = require("electron"); await shell.openExternal("https://electronjs.org"); }, },
-
acclerator:绑定快捷键
菜单栏里的选项都可以绑定快捷键,且 role 自动都帮忙配置好了,如果要自己配置快捷键,只要如下配置即可。
accelerator: isMac ? 'Alt+Cmd+I' : 'Alt+Shift+I',
建立起数据结构后,用 Menu 对象进行创建。
macOS 适配
里面还有个 isMac,用来判断当前系统是否是 macOS 系统。如果是 macOS 系统,就会多一个 label 为 app.name
的菜单。为啥要这样做,等下文的显示效果出来就知道了。
5.2 在主进程中引用菜单栏并生效
当 app 准备好后,生成菜单栏。
main.js 部分代码如下:
app.whenReady().then(() => {
createWindow();
// 创建菜单栏
Menu.setApplicationMenu(menu);
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
5.3 显示效果
启动后看一下菜单栏的显示效果:
可以看出是一一对应的,我因为把 about 的 label 设置为了“关于”,菜单栏上才显示自己定义的“关于”字样。
苹果系统因为软件一定会有一个 app.name
的菜单选项,并且系统会自定义菜单选项,因此自定义 app.name
菜单是挺有必要的。
6. electron 右键菜单
右键点击出现菜单事件在渲染进程中书写。因为菜单栏的创建需要调用主进程的方法,因此需要调用 remote。
// render/demo.js
const { BrowserWindow, Menu, getCurrentWindow } = require("@electron/remote");
const btn = document.querySelector("#btn");
const createWindow = () => {
const win = new BrowserWindow({
width: 500,
height: 500,
});
win.loadFile("newPage.html");
};
window.onload = function () {
btn.addEventListener("click", createWindow);
};
// 右键菜单内容,remote 的 Menu 不支持 role,有点麻烦
const menuList = [
{ role: "copy", label: "复制", accelerator: "cmd+c" },
{ role: "paste", label: "粘贴", accelerator: "cmd+d" },
];
const contextmenu = Menu.buildFromTemplate(menuList);
// 右键触发事件
window.addEventListener("contextmenu", (e) => {
// 阻止默认行为
e.preventDefault();
contextmenu.popup({ window: getCurrentWindow() });
});
实现效果:
7. 通过链接打开浏览器
7.1 默认情况
现在渲染页面的 HTML 如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>
<a id="baidu" href="https://www.baidu.com">百度一下</a>
</h1>
<script src="./render/demo2.js"></script>
</body>
</html>
那么在 electron 中点击 a 标签的默认效果是,在当前窗口中打开。
7.2 在浏览器中打开网页
如果想要点击 a 标签后,页面在默认的浏览器中打开而不是当前的 electron 窗口,就需要用到 shell.openExternal
渲染进程中这样写:
const { shell } = require("electron");
const baidu = document.getElementById("baidu");
baidu.addEventListener("click", (e) => {
e.preventDefault();
// 获取当前元素的 href
const baiduHref = baidu.getAttribute("href");
shell.openExternal(baiduHref);
});
便可以在本地的默认浏览器打开百度网页。
8. electron 嵌入网页和打开子窗口
8.1 嵌入网页
在主进程里这样写就行:
// 创建窗口函数
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 集成 node
nodeIntegration: true,
// 关闭上下文隔离,兼容 require 引入
contextIsolation: false,
},
});
// 创建并在页面内设置内嵌网页
const view = new BrowserView();
win.setBrowserView(view);
// 设置 view 样式和属性
view.setBounds({
x: 50,
y: 100,
width: 400,
height: 300,
});
// 加载百度网页
view.webContents.loadURL("https://www.baidu.com");
// 加载 index.html
win.loadFile("demo2.html");
// 打开开发工具
// mainWindow.webContents.openDevTools()
};
使用 BrowserView 类创建实例 view,然后窗口设置 view 并设置相关的属性,如在窗口里的坐标和显示的长宽等。
显示效果如下:
8.2 打开子窗口
现在在渲染进程里写点击按钮后,打开子窗口的事件:
这里使用 window.open 方法来打开。这个方法默认是在一个新窗口里打开的。
// render/demo2.js
const mybtn = document.getElementById("mybtn");
mybtn.addEventListener("click", (e) => {
window.open("https://www.baidu.com");
});
显示效果如下:
9. 子窗口向父窗口通信
9.1 父窗口页面代码
渲染进程的父窗口改成这样:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<div id="mytext"></div>
<button id="mybtn">打开子窗口</button>
<script src="./render/demo2.js"></script>
</body>
</html>
有一个按钮用来打开子窗口,然后 #mytest 用来接受父窗口传递过来的信息。
9.2 父窗口打开子窗口
常规代码,就不多说了
// render.js
const mybtn = document.getElementById("mybtn");
mybtn.addEventListener("click", (e) => {
window.open("children.html");
});
9.3 子窗口页面代码
因为子窗口的代码比较少,所以 js 代码也写在了 html 文件中。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2>我是子窗口</h2>
<button id="childrenBtn">向父窗口传递信息</button>
</body>
<script>
const childrenBtn = document.getElementById("childrenBtn")
childrenBtn.addEventListener('click', (e) => {
// 子窗口传递信息给父窗口
window.opener.postMessage('我是子窗口传递过来的信息')
})
</script>
</html>
子窗口当点击按钮的时候,触发监听事件,监听事件将会通过 window.opener.postMessage
传递信息到父窗口。
9.3 父窗口接受子窗口传递的信息
通过监听 message 事件触发回调,回调里有一个参数 message,message.data 即为子窗口传递过来的数据。
接受到数据后,用 innerHTML 显示到窗口上即可。
// render/demo2.js
window.addEventListener("message", (message) => {
const mytext = document.getElementById("mytext");
mytext.innerHTML = message.data;
});
最终效果
10. 启用文件对话框
启用一个新窗口,名称为 dialog-test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<button id="openBtn">点击按钮选择文件</button>
<img id="img" src="" alt="">
</body>
<script src="../render/dialog-test.js"></script>
</html>
期望的目标是,点击按钮后弹出文件对话框,只能选择图片。选择之后可以将图片显示到窗口中。
接下来讲一下流程:
- 因为调用文件对话框需要用到主进程方法,因此得从 remote 中引用 dialog
- 接着,点击按钮后触发事件,
dialog.showOpenDialog
就是打开文件对话框的方法,里边的参数有对话框标题、限制的文件类型、确认按钮自定义文本、选择多个文件等。这是个异步方法,用户选择完后返回结果 result。 - 本测试代码是单选图片,因此获取图片的路径只需要
result.filePaths[0]
即可。
对应的渲染进程 js 代码如下:
// render/dialog-test.js
const { dialog } = require("@electron/remote");
const openBtn = document.getElementById("openBtn");
openBtn.addEventListener("click", async () => {
// 这个方法是异步的,返回的是用户选择的文件
try {
const result = await dialog.showOpenDialog({
// 文件对话框标题
title: "请选择文件",
// 限制文件类型
filters: [{ name: "Images", extensions: ["jpg", "png", "gif"] }],
// 自定义按钮
buttonLabel: "打开图片",
});
const img = document.getElementById("img");
img.setAttribute("src", result.filePaths[0]);
} catch (error) {
console.log(error);
}
});
显示效果:
11. 保存文件对话框和保存文件操作
保存文件对话框样子本来就和文件对话框很像,使用 dialog.showSaveDialog
便可以生成保存文件对话框,同时这个方法也是异步的,用户在点击保存后返回结果 result,其中 result.filePath
为保存路径。
下面要实现一个功能,存储文件后,将 “hello” 写到文件里。
实现的代码如下:
// render/dialog-test.js
const saveBtn = document.getElementById("saveBtn");
saveBtn.addEventListener("click", async () => {
try {
const result = await dialog.showSaveDialog({
title: "保存文件",
});
// result.filePath 是保存的路径
fs.writeFile(result.filePath, "hello", (error) => {
if (error) {
console.log(`创建失败:${error}`);
} else {
console.log("创建成功");
}
});
} catch (error) {
console.log(error);
}
});
显示效果:
12. electron 消息对话框
上面的文件对话框和保存对话框是特殊的消息对话框,现在介绍一下常规的消息对话框。
消息对话框打开方式:dialog.showMessageBox
。用法和上面的基本相同。
重点在于 buttons,如果点击 buttons 里的第一个元素,那么返回值 result.response
的值为 0,第二个元素为 1,以此类推。
// render/dialog-test.js
const messageBtn = document.getElementById("messageBtn");
messageBtn.addEventListener("click", async () => {
try {
const result = await dialog.showMessageBox({
// 对话框类型
type: "info",
title: "这是个普通的对话框",
message: "点击啥反应没有",
// 按钮显示文本,value 值为 index,重点
buttons: ["不点了", "点一下", "点我"],
});
const value = result.response;
// ......
} catch (error) {
console.log(error);
}
});
关于处理的代码就不写了,根据 value 值判断然后做相应的逻辑即可。
显示效果:
13. electron 断网测试
没啥难度,就是得需要知道两个事件,一个是 online 事件,一个是 offline 事件,在渲染进程里监听即可。
// render/online-check.js
// offline -> online 网络连接的瞬间触发
window.addEventListener("online", () => {
alert("恢复网络~~~");
});
// on-line -> offline 断网的瞬间触发
window.addEventListener("offline", () => {
alert("断网了...");
});
断网效果:
联网效果同理。
14. 消息通知
消息通知本质上是 HTML5 内容,网页端也可以实现。
js 代码如下:
const notifyBtn = document.getElementById("notifyBtn");
notifyBtn.addEventListener("click", () => {
const option = {
title: "消息标题",
body: "消息内容",
// icon: "通知图标 URL"
};
new window.Notification(option.title, option);
});
15. electron 注册全局快捷键
全局快捷键,例如 vscode 打开资源管理器栏和快捷搜索文件等操作,用快捷键就可以呼出。
全局快捷键是全局注册且得用到主线程方法,因此在主进程里注册即可。必须在 app ready 之后注册!!!
注册快捷键关键代码:
// 注册全局快捷键
globalShortcut.register("CommandOrControl+E", () => {
win.loadURL("https://www.baidu.com");
});
};
接受两个参数,第一个参数是快捷键组合,第二个参数是触发快捷键后的回调。上面的意思是,按下 cmd/ctrl + e,窗口加载百度主页。
注意:**全局快捷键意思就是,在操作系统的全局都生效这个快捷键。**比如,我在网易云音乐界面选歌的时候 cmd+e 一下,启动的 app 也会加载百度网页,这很有可能占用了其他 app 的快捷键。因此,在 app 退出的时候需要注销快捷键,释放全局对快捷键的绑定。
解除绑定的关键代码:
app.on('will-quit', () => {
// 注销快捷键
// globalShortcut.unregister('CommandOrControl+X')
// 注销所有快捷键
globalShortcut.unregisterAll()
})
主进程所有代码如下:
// 引入 app 和窗口引用
const {
app,
BrowserWindow,
Menu,
BrowserView,
globalShortcut,
} = require("electron");
const { menu } = require("./main/menu");
// 初始化 remote
require("@electron/remote/main").initialize();
// 创建窗口函数
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 集成 node
nodeIntegration: true,
// 关闭上下文隔离,兼容 require 引入
contextIsolation: false,
},
});
// 加载 HTML 文件
win.loadFile("./pages/notification.html");
// 注册全局快捷键
globalShortcut.register("CommandOrControl+E", () => {
win.loadURL("https://www.baidu.com");
});
};
// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {
createWindow();
// 创建菜单栏
Menu.setApplicationMenu(menu);
app.on("activate", () => {
// On macOS it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 开启 remote
app.on("browser-window-created", (_, window) => {
require("@electron/remote/main").enable(window.webContents);
});
// 除了 macOS 外,当所有窗口都被关闭的时候退出程序。 There, it's common
// for applications and their menu bar to stay active until the user quits
// explicitly with Cmd + Q.
app.on("window-all-closed", () => {
if (process.platform !== "darwin") app.quit();
});
app.on('will-quit', () => {
// 注销快捷键
// globalShortcut.unregister('CommandOrControl+X')
// 注销所有快捷键
globalShortcut.unregisterAll()
})
// In this file you can include the rest of your app's specific main process
// code. 也可以拆分成几个文件,然后用 require 导入。
判断全局快捷键是否已经注册
const isReigistered = globalShortcut.isRegistered('CommandOrControl+X')
根据返回的布尔值来判断对应的快捷键是否注册成功,这个可以避免快捷键冲突问题。
16. 剪贴板功能使用
剪贴板功能常用于点击某个按钮来让 app 帮你复制一段内容,例如激活码、邀请码等。剪贴板的调用要用到 electron 里的 clipboard 对象。
剪贴板里写入内容只需要调用 clipboard.writeText
方法即可。
<body>
<div>
激活码: <span id="code">f43ojt8h39ghjoh843g8h</span>
<button id="btn">点击复制激活码</button>
</div>
</body>
const { clipboard } = require("@electron/remote");
const code = document.getElementById("code");
const btn = document.getElementById("btn");
btn.addEventListener("click", () => {
// 剪贴板写入内容
clipboard.writeText(code.innerHTML);
new window.Notification("复制成功", { body: "提示内容" });
});
点击显示效果:
文本也成功地贴到了剪贴板里。