跳转至

从渲染器打开窗口

有多种方式可以控制如何从渲染器中的可信或不可信内容创建窗口。窗口可以通过两种方式从渲染器创建:

  • 点击带有 target=_blank 的链接或提交带有该属性的表单
  • JavaScript 调用 window.open()

对于同站内容,新窗口会在同一进程中创建,从而使父窗口能够直接访问子窗口。这对于充当偏好设置面板或类似功能的应用程序子窗口非常有用,因为父窗口可以直接渲染到子窗口,就像渲染到父窗口中的某个 div 一样。这与浏览器中的行为相同。

进程级别的 webPreferences(如 sandbox 和 nodeIntegration)在渲染器进程启动时就被固化到该进程中,因此沙盒状态与打开者进程不同的子窗口无法共享该进程。在这种情况下,子窗口会在其自己的进程中创建,并且与打开者之间没有 opener 关系:在打开者中 window.open() 返回 null,在子窗口中 window.opener 为 null。子窗口默认处于沙盒状态,因此来自非沙盒打开者(例如启用了 nodeIntegration: true 的打开者)的 window.open() 默认会以这种方式隔离。若要让子窗口保留在打开者的进程中,请在从 webContents.setWindowOpenHandler 返回的 webPreferences 中显式设置 sandbox: false。

Electron 在底层将这种原生 DOM Window 与 BrowserWindow 配对。通过对渲染器创建的窗口使用 webContents.setWindowOpenHandler(),你可以充分利用在主进程中创建 BrowserWindow 时可用的所有自定义选项。

BrowserWindow 构造选项按优先级从低到高的顺序依次由以下来源设置:从 window.open() 的 features 字符串解析出的选项、从父窗口继承的与安全相关的 webPreferences,以及由 webContents.setWindowOpenHandler 给出的选项。请注意,webContents.setWindowOpenHandler 拥有最终决定权和完全权限,因为它是在主进程中调用的。

window.open(url[, frameName][, features])

  • url string
  • frameName string(可选)
  • features string(可选)

返回 Window | null

features 是一个逗号分隔的键值列表,遵循浏览器的标准格式。为方便起见,Electron 会从该列表中解析一部分表示性的 BrowserWindowConstructorOptions(如 width、height、x、y、show、frame、title、backgroundColor)。由于渲染器是不可信的,因此那些会导致主进程访问文件系统或具有其他特权的选项(如 icon)会被忽略。为了获得完全控制和更好的可用性,请使用 webContents.setWindowOpenHandler 在主进程中自定义 BrowserWindow 的创建。

WebPreferences 的一个子集可以直接从 features 字符串中以非嵌套方式设置:zoomFactor、nodeIntegration、javascript、contextIsolation 和 webviewTag。

例如:

window.open('https://github.com', '_blank', 'top=500,left=200,frame=false,nodeIntegration=no')

注意:

  • 如果父窗口禁用了 Node integration,则在打开的 window 中也会始终禁用 Node integration。
  • 如果父窗口启用了 Context isolation,则在打开的 window 中也会始终启用 Context isolation。
  • 如果父窗口禁用了 JavaScript,则在打开的 window 中也会始终禁用 JavaScript。
  • 未由 Chromium 处理且不在 Electron 表示性 BrowserWindowConstructorOptions 允许列表中的 features 会被忽略。原始 features 字符串仍然可以通过 setWindowOpenHandler 提供给主进程。
  • frameName 遵循 原生文档 中 target 的规范。
  • 当打开 about:blank 时,子窗口的 WebPreferences 会从父窗口复制,且由于 Chromium 在这种情况下会跳过浏览器端导航,因此无法覆盖它。

要自定义或取消窗口的创建,你可以选择在主进程中通过 webContents.setWindowOpenHandler() 设置一个覆盖处理程序。返回 { action: 'deny' } 会取消窗口。返回 { action: 'allow', overrideBrowserWindowOptions: { ... } } 将允许打开窗口,并设置创建窗口时要使用的 BrowserWindowConstructorOptions。请注意,这比通过 feature 字符串传递选项更强大,因为渲染器在决定安全偏好方面的权限比主进程更有限。

除了传入 action 和 overrideBrowserWindowOptions 之外,还可以像这样传入 outlivesOpener:{ action: 'allow', outlivesOpener: true, overrideBrowserWindowOptions: { ... } }。如果设置为 true,则当打开者窗口关闭时,新创建的窗口不会关闭。默认值为 false。

原生 Window 示例

// main.js
const mainWindow = new BrowserWindow()

// In this example, only windows with the `about:blank` url will be created.
// All other urls will be blocked.
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
  if (url === 'about:blank') {
    return {
      action: 'allow',
      overrideBrowserWindowOptions: {
        frame: false,
        fullscreenable: false,
        backgroundColor: 'black',
        webPreferences: {
          preload: 'my-child-window-preload-script.js'
        }
      }
    }
  }
  return { action: 'deny' }
})
// renderer process (mainWindow)
const childWindow = window.open('', 'modal')
childWindow.document.write('<h1>Hello</h1>')

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 el/electron