在 Electron 中卸载前确认

Confirm beforeunload in Electron

我知道有数百个问题,例如:"How can i prevent close event in electron" 或类似的问题。
beforeunload 事件中实现确认框(电子消息框)后,我能够关闭我的应用程序并取消关闭事件。由于开发工具始终处于打开状态,我没有意识到在关闭开发工具时它不起作用...

window.onbeforeunload = e =>
{           
    // show a message box with "save", "don't save", and "cancel" button
    let warning = remote.dialog.showMessageBox(...) 

    switch(warning)
    {
        case 0:
            console.log("save");
            return;
        case 1:
            console.log("don't save");
            return;
        case 2:
            console.log("cancel");
            return false;
            // e.returnValue = "false";
            // e.returnValue = false;
    }
};

所以,当打开开发工具时,我可以关闭应用程序并保存,不保存并取消事件。
关闭开发工具后,取消按钮将不再起作用。

顺便说一句:

window.onbeforeunload = e =>
{           
    return false;
    alert("foo");
};

将取消关闭事件并且显然不会显示消息(无论开发工具是打开还是关闭都无所谓)

window.onbeforeunload = e =>
{           
    alert("foo");
    return false;
};

如果开发工具已打开,将在按确定后取消关闭事件;如果开发工具已关闭,将在按确定后关闭应用程序

我有意使用消息框的同步 api,在写这个问题时我发现一个双窗口应用程序 (new remote.BrowserWindow()) 的行为与开发工具。

有人知道我该如何解决这个问题吗?
非常感谢

而不是 onbeforeunload 更喜欢使用事件 close。从此事件中,您将能够在整个关闭过程完成之前捕获关闭事件(事件 closed)。使用 close,您将能够控制并在需要完成关闭时停止。

这在您创建 BrowserWindow 时是可能的,最好是在主进程中:

// Create the browser window.
window = new BrowserWindow({});

// Event 'close'
window.on('close', (e) => {
    // Do your control here
    if (bToStop) {
        e.preventDefault();
    }
})

// Event 'closed'
window.on('closed', (e) => {
    // Fired only if you didn't called e.preventDefault(); above!
})

此外,请注意函数 e.preventDefault() 正在整个代码中传播。如果你需要回到 Electron 的自然行为,你需要将变量 e.defaultPrevented 切换为 false.

实际上,e.preventDefault() 函数似乎正在处理变量 e.defaultPreventedtrue,直到它发生任何变化。

更新:

正如我在上面接受的答案的评论中提到的,preventDefault 在 Windows 上被忽略了。准确地说,我将它放在用户关闭应用程序时打开的本机电子对话框的回调中。

因此我采用了不同的方法:

let close: boolean = false    

win.on('close', (ev: any) => {

  if (close === false) {
    ev.preventDefault()

    dialog.showMessageBox({
      type: 'warning',
      buttons: ['Cancel', 'Ok'],
      title: 'Do not forget to safe your changes',
      cancelId: 0,
      defaultId: 1,
      noLink: true
    }).then((val) => {

      if (val.response === 0) {
        // Cancel the close process
      } else if (win) {
        close = true
        app.quit()
      }
    })
  }

})

也许这会帮助有类似需求的人,我有一个包含在电子应用程序中的反应应用程序,反应应用程序与电子无关,也可以 运行 在浏览器中和我的要求本来是要显示默认的浏览器提示,臭名昭著的 Leave Site? 警报。

在浏览器中这很容易,例如我只是这样做:

useEffect(() => {
   window.onbeforeunload = promptOnProjectLeave ? () => true : undefined;
    return () => {
        window.onbeforeunload = undefined;
    }
}, [promptOnProjectLeave]);

这将显示默认浏览器 Leave Site? 提示,但在电子中,这只会阻止 window 在没有任何操作提示询问您是否确定的情况下关闭,所以我的方法是这个 post 和另一个 .

的混合

这就是解决方案

mainWindow.webContents.on('will-prevent-unload', (event) => {
    const options = {
        type: 'question',
        buttons: ['Cancel', 'Leave'],
        message: 'Leave Site?',
        detail: 'Changes that you made may not be saved.',
    };
    const response = dialog.showMessageBoxSync(null, options)
    if (response === 1) event.preventDefault();
});

这将允许我在我的反应代码中使用 window.onbeforeunload 就像在浏览器中一样,在浏览器中我将获得默认的浏览器提示,在电子中我将获得一个消息框 :)

这是我第一次使用 Electron,因此可能有一些改进方法,但无论哪种方式,希望这对某人有所帮助,我知道当我开始这项任务时它会对我有所帮助。

您可以简单地使用 'pagehide' 事件。它似乎适用于电子应用程序。它的工作方式与 'beforeunload' 略有不同,因为它不能阻止关闭 window/tab,但是如果您只需要在页面关闭之前做一些事情(使用 navigator.sendBeacon() 发送一些异步请求等)那么这个活动可能会满足您的需求。

您可以阅读更多相关信息here, here and in the docs

用法示例:

window.addEventListener('pagehide', () => {
    window.navigator.sendBeacon(url, data);
}