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。

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐