Remote 模块的使用
当我们知道了 Electron 有主进程和渲染进程后,我们还要知道一件事,就是 Electron 的 API 方法和模块也是分为可以在主进程和渲染进程中使用。那如果我们想在渲染进程中使用主进程中的模块方法时,可以使用Electron Remote
解决在渲染和主进程间的通讯。
渲染进程中打开新窗口
在之前的 index.html 文件上修改如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title></title>
</head>
<body>
<h1>this is the main index.html</h1>
<button id="btn">打开新的窗口</button>
</body>
<script>
const { remote } = require("electron");
const btn = document.querySelector("#btn");
const BrowserWindow = require("electron").remote.BrowserWindow;
btn.onclick = () => {
let newWin = new BrowserWindow({
width: 300,
height: 400
});
newWin.loadFile("./new.html");
newWin.on("close", () => {
newWin = null;
});
};
</script>
</html>
::: tip
当我们在渲染进程中使用 remote,必须在主线程中将webPreferences.enableRemoteModule
设置为 true。否则将无法使用远程调用模块。
:::
菜单的基本使用
编写菜单模板
创建菜单模板的方式有两种:
- 通过
MenuItem
构造
const { Menu, MenuItem } = require("electron");
const menu = new Menu();
menu.append(
new MenuItem({
label: "Electron",
submenu: [
{
role: "Help",
accelerator:
process.platform === "darwin" ? "Alt+Cmd+H" : "Ctrl+Shift+H",
click: () => {
console.log(`111`);
}
}
]
})
);
new MenuItem([options])
options
Object (可选)click
Function (可选) - 回调函数,当被点击的时候触发。回调参数如下:menuItem
MenuItem-
browserWindow
BrowserWindowundefined - 窗口未打开时,其值为 undefined
。 event
KeyboardEvent
role
String (可选) - 可以是undo
,redo
,cut
,copy
,paste
,pasteAndMatchStyle
等等。 定义菜单项的行为,当传入的参数值是以上列举之一时,click 属性将被忽略。 参见 rolestype
String (可选)-可以是 normal、separator、submenu、checkbox 或 radio。label
String (可选)accelerator
String (可选) - 快捷键。 详参见 Accelerator-
submenu
(MenuItemConstructorOptions[]Menu) (可选)
- 通过一个和
MenuItem
配置参数一致数组对象和Menu.buildFromTemplate
构造
const BrowserWindow = require("electron").remote.BrowserWindow;
const template = [
{
label: "编辑",
sublabel: "desc",
submenu: [
{
label: "撤销",
accelerator: "Ctrl+Shift+Z",
click: () => {
console.log(`Undo`);
}
}
]
},
{
label: "打开新窗口",
click: () => {
let win = new BrowserWindow({
width: 200,
height: 300
});
win.loadFile("./new.html");
win.on("close", () => {
win = null;
});
}
}
];
const menu = Menu.buildFromTemplate(template);
创建顶部菜单
创建好了模板之后,在主线程中,我们就可以通过 Menu.setApplicationMenu( )方法来将创建顶部菜单
// main.js
...
Menu.setApplicationMenu(menu);
创建右键菜单
右键菜单的响应事件是写在渲染进程中的,也就是写在index.html
中的,所以要是使用,就用到到remote
模块进行操作了。
// index.html
...
const { remote } = require("electron")
const template = [
{ label: "刷新" },
{ label: "复制" },
{ label: "粘贴" },
{
label: "新建", submenu: [{
label: "文件夹",
accelerator: "Ctrl+Shift+Z",
click: (() => {
console.log(`Undo`)
})
}],
}
]
const contextmenu = remote.Menu.buildFromTemplate(template);
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
contextmenu.popup({ window: remote.getCurrentWindow() })
})
浏览器打开链接
默认案例演示
我们先来看一下,在 electron 中默认打开一个链接是什么样的,代码如下:
// index.html
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<a href="http://175.24.90.8:3200/">访问我的博客</a>
</body>
</html>
这时候我们运行程序,点击链接以后,可以看到是在窗口中直接打开的,而不是在浏览器中打开。我们现在要作的就是在浏览器中打开。
Shell 模块在浏览中打开链接
// index.html
<html lang="en">
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<a id="oLink" href="http://175.24.90.8:3200/">访问我的博客</a>
</body>
<script>
const { shell } = require("electron");
const oLink = document.querySelector("#link");
oLink.onclick = function(e) {
e.preventDefault();
const href = this.getAttribute("href");
if (href) {
shell.openExternal(href);
}
};
</script>
</html>
子窗口和父窗口之间的通讯
window.open
函数
打开一个新窗口并加载 URL。
当调用
window.open
以在网页中创建新窗口时,将为url
创建一个新的BrowserWindow
实例,并返回一个代理至window.open
以让页面对其进行有限的控制。
为了与传统的
web page
相兼容,这个代理只保留的标准的函数方法,若想完全控制新窗口,请直接使用BrowserWindow
方法。
新创建的
BroswerWindow
默认会继承父窗口的options
。若你想覆盖,请提供features
参数。
window.open(url[, frameName][, features])
url
String - 页面地址frameName
String(可选)features
String(可选)
创建一个新窗口,并返回一个 BrowserWindowProxy
类的实例。
features
字符串遵循标准浏览器的格式,但每个 feature
必须是BrowserWindow
选项中的字段。 例如: zoomFactor
, nodeIntegration
, preload
, javascript
, contextIsolation
, webviewTag
.
示例如下:
window.open("http://175.24.90.8:3200/", "_blank", "nodeIntegration=no");
注意:
- 如果在父窗口中禁用了 Node integration, 则在打开的
window
中将始终被禁用。 - 如果在父窗口中启用了上下文隔离, 则在打开的
window
中将始终被启用。 - 父窗口禁用 Javascript,打开的
window
中将被始终禁用 features
中给定的非标准特性 (不由 Chromium 或 Electron 处理) 将被传递到 additionalFeatures 参数中的任何已注册 webContent 的 new-window 事件处理程序。
子父窗口之间的通讯
window.opener.postMessage()子窗口向父窗口传递消息
window.opener.postMessage(message,targetOrigin)
,是将消息发送给指定来源的父窗口,如果未指定来源则发送给*
,即所有窗口。
message
: 传递的消息,是 String 类型的值targetOrigin
: 指定发送的窗口
新建一个popup.html
。当点击按钮的时候向父窗口传递消息
// popup.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>popup_page</title>
</head>
<body>
<h1>我是popup的子窗口</h1>
<button id="popBtn">向父窗口传递信息</button>
</body>
<script type="text/javascript">
const oBtn = document.querySelector("#popBtn");
oBtn.onclick = function(e) {
window.opener.postMessage("this is message from popup_page");
};
</script>
</html>
在index.html
中打开popup.html
并监听message
事件
// index.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>Remote</title>
</head>
<body>
<button id="btn">window.open打开新的窗口</button>
接收到的消息是:
<p id="text"></p>
</body>
<script>
iframeBtn.onclick = function() {
window.open("./popup.html");
};
window.addEventListener("message", msg => {
const oText = document.querySelector("#text");
oText.innerHTML = msg.data;
});
</script>
</html>
BrowserWindowProxy
操纵子浏览器窗口 使用
window.open
创建一个新窗口时会返回一个BrowserWindowProxy
对象,并提供一个有限功能的子窗口.
实例方法
BrowserWindowProxy
对象具有以下实例方法:
win.blur()
将焦点从子窗口中移除.
win.close()
不调用卸载事件,便关闭了子窗口。
win.focus()
聚焦子窗口(即窗口置顶)
实例属性
BrowserWindowProxy
对象具有以下实例属性:
win.closed
在子窗口关闭后设置为 true 的 Boolean
。
嵌入网页 BroswerView
创建和控制视图
BrowserView
被用来让 BrowserWindow
嵌入更多的 web 内容。 它就像一个子窗口,除了它的位置是相对于父窗口。 这意味着可以替代webview
标签.
这很类似 Web 中的<iframe>
标签。需要注意的是 BrowserView 是主进程中的类,所以只能在主进程中使用。
打开根目录下打开main.js
,直接引入并使用 BrowserView 就可以实现键入网页到应用中。
const { BrowserView } = require("electron");
const view = new BrowserView();
mainWindow.setBrowserView(view);
view.setBounds({ x: 20, y: 200, height: 500, width: 400 });
view.webContents.loadURL("http://175.24.90.8:3200/");
new BrowserView([options])
options
Object (可选)webPreferences
Object (可选) - 详情请看 BrowserWindow.
实例方法
使用 new BrowserView
创建的对象具有以下实例方法:
-
view.setBounds(bounds)
实验功能bounds
Retanglex
Number (必填) - 相对于主窗口左上角的 x 轴坐标y
Number (必填) - 相对于主窗口左上角的 y 轴坐标width
Number (必填) - 矩形窗口的宽度height
Number (必填) - 矩形窗口的高度
调整视图的大小,并将它移动到窗口边界
view.getBounds(bounds)
实验功能
返回 Rectangle
-
view.setAutoResize(options)
实验功能options
Object (可选)width
Boolean (可选) - 网页的宽度是否跟随窗口的变化而变化height
Boolean (可选) - 网页的高度是否跟随窗口的变化而变化horizontal
Boolean (可选) - 网页的宽度和 x 轴坐标是否跟随窗口的变化而变化vertical
Boolean (可选) - 网页的高度和 y 轴坐标是否跟随窗口的变化而变化
配置视图改变时,网页的缩放规则
view.setBackgroundColor(color)
实验功能
设置网页窗口的背景颜色
Dialog
::: tip 显示用于打开和保存文件、警报等的本机系统对话框。详情 :::
dialog.showOpenDialog([browserWindow,]options)
browserWindow
BrowserWindow (可选)options
Object (必填)
返回Promise<Object>
Object 包含以下成员:
canceled
Boolean 用户是否点击了弹框内的取消按钮filePaths
String[] - 用户选择的文件路径的数组. 若用户点击取消,则返回空数组。
browserWindow
参数允许该对话框将自身附加到父窗口, 作为父窗口的模态框。
filters
表明了哪些文件是可以被选取的,例如:
...
{
filters: [
{ name: 'Images', extensions: ['jpg', 'png', 'gif'] },
{ name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
{ name: 'Custom File Type', extensions: ['as'] },
{ name: 'All Files', extensions: ['*'] }
]
}
下面的例子标明了如何在渲染进程中打开一个文件选取对话框
const { dialog } = require("electron").remote;
dialog
.showOpenDialog({
title: "请选择图片",
buttonLabel: "打开这个",
filters: [{ name: "jpg", extensions: ["jpg"] }]
})
.then(data => {
console.log(data.canceled, data.filePaths);
});
dialog.showSaveDialog([browserWindow,]options)
browserWindow
BrowserWindow (可选)options
Object (必填)
返回Promise<Object>
Object 包含以下成员:
canceled
Boolean 用户是否点击了弹框内的取消按钮-
filePath
StringUndefined - 文件保存的路径。 若用户点击取消,则返回 undefined。
下面的例子展示了如何保存文件并写入内容
const fs = require("fs");
const { dialog } = require("electron").remote;
dialog
.showSaveDialog({
title: "保存文件"
})
.then(data => {
if (!data.canceled) {
fs.writeFileSync(data.filePath, "这是我用fs模块保存的文件啊");
}
})
.catch(err => {
console.error(err);
});
dialog.showErrorBox(title,content)
title
String - 显示在错误框中的标题.content
String - 显示在错误框中的文本内容.
显示一个显示错误消息的模态对话框。
这个 API 可以在 app
模块触发 ready
事件之前被安全地调用,它通常用在启动时报告错误。
dialog.showMessageBox([browserWindow,]options)
browserWindow
BrowserWindow (可选)options
Object (必填)type
String (可选) - 可以为none
,info
,error
,question
或者warning
. 在 Windows 上,question
与info
显示相同的图标, 除非你使用了 “icon” 选项设置图标。title
String (可选) - message box 的标题,一些平台不显示。message
String - message box 的内容。detail
String (可选) - 额外信息。buttons
String - 字符串组成的按钮数组,在 windows 中,若此参数为空,则会默认显示一个”OK”的按钮。checkboxLabel
String (可选) - 若值不为空,则 message box 会展示一个一个 checkbox,并将 label 设置为此值。checkboxChecked
Boolean (可选) - 是否默认选中 checkbox,默认 false。icon
NativeImage (可选) - 弹框的 icon 。noLink
Boolean (可选) - 是否不开启联想(尝试用本地所使用的语言去替换 Buttons 中的配置,例如 Yes 联想成(是 Y),Cancel 联想成取消)
。默认 false 有联想。
返回Promise<Object>
Object 包含以下成员:
response
Number 所点击的按钮的额索引checkboxChecked
Boolean - chechbox 的选中状态。
以下列子展示了如何打开一个消息对话框:
const { dialog } = require("electron");
dialog
.showMessageBox({
type: "error",
title: "confirm title",
message: "confirm message",
detail: "confirm details",
checkboxLabel: "我同意",
buttons: ["Yes", "Cancel", "OK"],
defaultId: 2,
noLink: false // 是否不开启联想(尝试用本地所使用的语言去替换Buttons中的配置,例如Yes联想成(是Y),Cancel联想成取消)。默认false有联想
})
.then(res => {
console.log(res, res.response, res.checkboxChecked);
});
检测网络状态
使用 js 监听网络状态的变化
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h2> 断网提醒测试 </h2>
</body>
<script>
window.addEventListener('online',function(){
alert('我来了,我们继续哦!')
})
window.addEventListener('offline',function(){
alert('先行离开一会,请稍等!')
})
</script>
</html>
Notification
展示如何创建一个消息通知
在主进程中
const { Notification } = require("electron");
const notification = {
title: "Basic Notification",
body: "Notification from the Main process"
};
new Notification(notification).show();
在渲染进程中进程中
new window.Notification("tips", {
body: "notification from the render process"
});
键盘快捷键
全局快捷键
示例如下:
const { app, BrowserWindow, globalShortcut } = require("electron");
let mainWindow = null;
app.on("ready", () => {
mainWindow = new BrowserWindow({
width: 1200,
height: 800
});
globalShortcut.register("Ctrl+N", () => {
mainWindow.loadURL("http://175.24.90.8:3200/");
});
const isRegister = globalShortcut.isRegistered("Ctrl+N"); // 查看快捷键是否注册成功
});
app.on("will-quit", () => {
// 退出时注销全局的快捷键
globalShortcut.unregister("Ctrl+N");
globalShortcut.unregisterAll();
});
剪切板
示例如下:
<!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>Clipboard</title>
</head>
<body>
激活码 <span id="code">sdmaspdmasopdopas</span>
<br />
<button id="btn">点击复制</button>
</body>
<script type="text/javascript">
const { clipboard } = require("electron");
const oCode = document.querySelector("#code");
const oBtn = document.querySelector("#btn");
oBtn.onclick = () => {
clipboard.writeText(oCode.innerText);
alert("复制成功");
};
</script>
</html>
自定义 Windows 任务栏
弹出列表
::: tip
Windows 允许应用程序自定义一个菜单栏,当用户右键单击任务栏中的应用图标可以看到该菜单栏。 该上下文菜单被成为弹出列表
。
:::
示例如下:
const { app } = require("electron");
app.setUserTasks([
{
program: process.execPath,
arguments: "--new-window",
iconPath: process.execPath,
iconIndex: 0,
title: "New Window For Custome",
description: "Create a new window By Electron Api "
}
]);
app.setUserTasks([]); // 清空任务栏列表
闪烁框
在 Windows 上,你可以突出显示任务栏按钮以获得用户的关注。 这与在 macOS 上 dock 弹跳图标相似。
引自 MSDN:
通常, 会闪现一个窗口, 通知用户该窗口需要注意, 但是该窗口当前没有键盘焦点。
要在 BrowserWindow 的任务栏按钮突出显示,可以使用 BrowserWindow.flashFrame API
。
示例如下:
const { BrowserWindow } = require("electron");
const win = new BrowserWindow();
win.once("focus", () => win.flashFrame(false));
win.flashFrame(true);
注意:别忘了调用
win.flashFramework(false)
来关闭闪烁。 在上面的示例中, 当窗口进入焦点时会调用它, 但您可能会使用超时或其他一些事件来禁用它。