Electron常用API window.open及父子窗口和模态窗口
Electron中父子窗口、模态窗口及window.open() api的使用
window.open
打开一个新窗口并加载 URL。
当调用 window.open 以在网页中创建新窗口时,将为url 创建一个新的BrowserWindow 实例,并返回一个代理至 window.open 以让页面对其进行有限的控制。
window.open(url,frameName,features)
- url String
- frameName String(可选)
- features String(可选)
Returns BrowserWindowProxy - 创建一个新窗口,并返回一个 BrowserWindowProxy 类的实例。
features 字符串遵循标准浏览器的格式,但每个 feature 必须是BrowserWindow 选项中的字段。 These are the features you can set via features string: zoomFactor, nodeIntegration, preload, javascript, contextIsolation, webviewTag.
例如:
window.open('https://github.com', '_blank', 'nodeIntegration=no')
注意:
- 如果在父窗口中禁用了 Node integration, 则在打开的 window 中将始终被禁用。
- 如果在父窗口中启用了上下文隔离, 则在打开的 window 中将始终被启用。
- 父窗口禁用 Javascript,打开的 window 中将被始终禁用
- features 中给定的非标准特性 (不由 Chromium 或 Electron 处理) 将被传递到 additionalFeatures 参数中的任何已注册 webContent 的 new-window 事件处理程序。
window.opener.postMessage(message, targetOrigin)
- message String
- targetOrigin String
将消息发送给指定来源的父窗口,如果未指定来源则发送给*,即所有窗口。
使用 Chrome 的 window.open()
如果要使用 Chrome 的内置 window.open(),请在 webPreferences 选项中将 nativeWindowOpen 设置为 true。
原生 window.open () 允许同步打开窗口, 因此可以方便的选择是对话框还是首选项窗口。
该选项也可以设置在<webview>标签上:
<webview webpreferences="nativeWindowOpen=yes"></webview>
BrowserWindow的创建可通过WebContents 的 new-window事件进行定制 。
// main process
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nativeWindowOpen: true
}
})
mainWindow.webContents.on('new-window', (event, url, frameName, disposition, options, additionalFeatures) => {
if (frameName === 'modal') {
// open window as modal
event.preventDefault()
Object.assign(options, {
modal: true,
parent: mainWindow,
width: 100,
height: 100
})
event.newGuest = new BrowserWindow(options)
}
})
// renderer process (mainWindow)
const modal = window.open('', 'modal')
modal.document.write('<h1>Hello</h1>')
例: 打开一个子窗口并向父窗口传递消息
主线程脚本
main.js
//为了管理应用程序的生命周期事件以及创建和控制浏览器窗口,您从 electron 包导入了 app 和 BrowserWindow 模块 。
const { app, BrowserWindow } = require('electron')
//在此之后,你定义了一个创建 新的浏览窗口的函数并将 nodeIntegration 设置为 true,将 index.html 文件加载到窗口中(第 12 行,稍后我们将讨论该文件)
function createWindow () {
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
//开启webview 标签 Electron >= 5 后需要开启
webviewTag:true,
nodeIntegration: true
}
})
win.loadFile('index.html')
}
//你通过调用 createWindow方法,在 electron app 第一次被初始化时创建了一个新的窗口。
app.whenReady().then(createWindow)
//您添加了一个新的侦听器,当应用程序不再有任何打开窗口时试图退出。 由于操作系统的 窗口管理行为 ,此监听器在 macOS 上是禁止操作的
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
//您添加一个新的侦听器,只有当应用程序激活后没有可见窗口时,才能创建新的浏览器窗口。 例如,在首次启动应用程序后或重启运行中的应用程序
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
主窗口
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<style>
.for_file_drag{
width: 100%;
height: 400px;
background-color: pink;
}
</style>
</head>
<body>
<h1>window open 函数</h1>
<button onclick="openChildWindow()">点击弹出子窗口</button>
</body>
<script>
//打开当前目录child.html 为子窗口
function openChildWindow() {
window.open('child.html', '_blank')
}
//添加消息监听
window.addEventListener('message', (e) => {
console.log('接受到的消息:'+ e.data);
});
</script>
</html>
子窗口
child.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子窗口</title>
</head>
<body>
<h1>这是子窗口</h1>
<button onclick="sendParentMsg()">向父窗口回传信息</button>
</body>
<script>
function sendParentMsg() {
window.opener.postMessage('test');
}
</script>
</html>
效果
例:打开子窗口的另一种方式
main.js
const { app, BrowserWindow } = require('electron')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
show: false,
// frame: true,
// autoHideMenuBar: true,
title: "Samve",
// icon: "",
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
enableRemoteModule: true
}
})
require('@electron/remote/main').initialize()
require("@electron/remote/main").enable(win.webContents)
win.loadFile('index.html')
win.on("ready-to-show", function(){
win.show();
})
}
app.on("ready", function(){
createWindow();
})
app.on("window-all-closed", function(){
app.quit();
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<h1>父窗口</h1>
<div><button id="btn">打开</button></div>
<script src="render.js"></script>
</body>
</html>
render.js
const remote = require("@electron/remote")
window.addEventListener("DOMContentLoaded", () => {
const oBtn = document.getElementById("btn");
oBtn.addEventListener("click", () => {
let subWin = new remote.BrowserWindow({
parent: remote.getCurrentWindow(),
width: 500,
height: 300
})
console.log("loadFile");
subWin.loadFile("sub.html");
subWin.on("close", () => {
subWin = null;
})
})
})
sub.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
子页面
</body>
</html>
例:在父窗口中控制关闭子窗口
在第一个例子中演示打开窗口并回传信息,那如果要在主窗口中关闭子窗口怎么做呢?这时候就要用
BowserWindowProxy对象了
Returns BrowserWindowProxy - 创建一个新窗口,并返回一个
BrowserWindowProxy
类的实例。
这个对象是创建新窗口返回的
api参考:
https://www.electronjs.org/docs/api/browser-window-proxy
将上面的主窗口代码稍微改下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<style>
.for_file_drag{
width: 100%;
height: 400px;
background-color: pink;
}
</style>
</head>
<body>
<h1>window open 函数</h1>
<button onclick="openChildWindow()">点击弹出子窗口</button>
<button onclick="closeChildWindow()">点击关闭子窗口</button>
</body>
<script>
let childBowserWindowProxy = null;
//打开当前目录child.html 为子窗口
function openChildWindow() {
childBowserWindowProxy = window.open('child.html', '_blank')
}
//关闭当前窗口
function closeChildWindow(){
childBowserWindowProxy.close();
}
//添加消息监听
window.addEventListener('message', (e) => {
console.log('接受到的消息:'+ e.data);
});
</script>
</html>
关于window open函数的疑问
在第二例子中,我发现不管我点击几次弹出子窗口,app只会弹出一个子窗口,这是为什么呢?
经过一阵研究发现,只要window.open 的第二个参数也就是frameName参数一致,它就会始终只有一个
例如这种只会有一个
//打开当前目录child.html 为子窗口
function openChildWindow() {
childBowserWindowProxy = window.open('child.html', '_blank')
}
但是这种会点击几个创建几个
//打开当前目录child.html 为子窗口
function openChildWindow() {
childBowserWindowProxy = window.open('child.html', '_blank'+ new Date().getTime())
}
父子窗口
父子窗口(Mac OS X和Windows有一定差异)
- 1、子窗口总是在父窗口之上
- 2、如果父窗口关闭,子窗口自动关闭
子窗口相当于父窗口的悬浮窗口
Mac OS X和Windows的父子窗口的区别是:
- 在Mac OS X下,移动父窗口,子窗口会随着父窗口移动
- 在Windows下子窗口不会移动
main.js
/**
* 父子窗口(Mac OS X和Windows有一定差异)
* 1、子窗口总是在父窗口之上
* 2、如果父窗口关闭,子窗口自动关闭
*
* 子窗口相当于父窗口的悬浮窗口
* Mac OS X和Windows的父子窗口的区别是:
* 在Mac OS X下,移动父窗口,子窗口会随着父窗口移动
* 在Windows下子窗口不会移动
*/
const {
app,
BrowserWindow
} = require('electron')
function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
// frame: false,
webPreferences: {
// preload: path.join(__dirname, 'preload.js'),
nodeIntegration: true,
contextIsolation: false
}
})
win.loadFile('index.html')
childWin = new BrowserWindow({
parent: win, width: 400, height: 300,
//module:true
});
childWin.loadFile('child.html');
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<style>
.for_file_drag{
width: 100%;
height: 400px;
background-color: pink;
}
</style>
</head>
<body>
<h1>父窗口</h1>
</body>
</html>
child.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>子窗口</title>
</head>
<body>
<h1>这是子窗口</h1>
</body>
</html>
模态窗口(Mac OS X和Windows差异比较大)
模态窗口是指禁用父窗口的子窗口,也就是说,处于模态的子窗口显示后,无法使用父窗口,直到子窗口关闭。
1、模态窗口需要是另外一个窗口;
2、一旦模态窗口显示,父窗口将无法使用。
modal=true
Mac OS X 和Windows的模态窗口差异:
1、模态窗口在Mac OS X下会隐藏的标题栏,只能通过close方法关闭模态子窗口
在Windows下,模态子窗口仍然会显示菜单和标题栏
2、在Mac OS X下,模态子窗口显示后,父窗口仍然可以拖动,但无法关闭,在Windows下,模态子窗口显示后父窗口无法拖动
应用:主要用于桌面应用的对话框显示,如设置对话框、打开对话框。
代码示例,同父子窗口,只是子窗口多了一个modal属性,其值为true。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)