Electron:如何在 2021 年通过 js 关闭应用程序?

Electron :how to close app via js in 2021?

我想用js关闭Electron App

"electron": "^13.1.7"

我仔细看了那些问题:

但是 none 对我有用。


以下所有测试均基于the offical electron-quick-start

  1. 根据上述问题的答案,我得到了这些代码:

index.html

  <body>
    <button id="close-app">
        close
    </button>
    <script src="./renderer.js"></script>
  </body>

main.js

const {BrowserWindow, remote} = require('electron')
...
app.whenReady().then(() => {
  ...
  app.on('activate', function () {
    ...
    document.getElementById("close-app").addEventListener("click", function (e) {
      remote.getCurrentWindow().close()
    })
  })
})

没有任何影响或错误。

好像代码从来没有运行,我在addEventListener上面加了一个console.log('run'),控制台也没有打印出来


  1. 根据document,我得到了这些代码:

(不更改 the offical electron-quick-start,仅更改 preload.jsindex.html

index.html

同上

preload.js

const { app } = require('electron');
window.addEventListener('DOMContentLoaded', () => {
  document.getElementById("close-app").addEventListener("click", function (e) {
      app.quit();
  })
})

只有Uncaught TypeError: Cannot read property 'quit' of undefined


那么,如何通过js关闭Electron App呢?

非常感谢任何人的帮助!

Electron 有只在主进程中工作的模块,如 app 和只在渲染进程中工作的模块,如 ipcRenderer 和通用的模块,可以在两者中 运行进程

我建议阅读解释流程模型的 Electron 文档 this article

Preload scripts contain code that executes in a renderer process before its web content begins loading. These scripts run within the renderer context, but are granted more privileges by having access to Node.js APIs.

因为app模块是一个主进程模块,如果你试图从预加载脚本(渲染进程)访问它,app将是未定义的

// in preload.js
const { app } = require('electron');

console.log(app); // undefined

相反,您应该使用进程间通信来告诉主进程退出

// in main.js
const { app, ipcMain } = require('electron');

ipcMain.handle('quit-app', () => {
  app.quit();
});

// in preload.js
const { ipcRenderer } = require('electron');

window.addEventListener('DOMContentLoaded', () => {
  document.getElementById('close-app').addEventListener('click', () => {
      ipcRenderer.invoke('quit-app');
  });
});

对于那些没有使用官方模板而是使用基于 Vue3 webpack 的 electron 的人。

您必须先在异步函数中创建 window,这将 return BrowserWindow()

创建的 win

main.js

import { BrowserWindow, ipcMain } from 'electron'

async function createWindow() {
    // Create the browser window.
    const win = new BrowserWindow({
        transparent: true,
        frame: false,
        webPreferences: {
            nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
            enableRemoteModule: true
        }
    })

    if (process.env.WEBPACK_DEV_SERVER_URL) {
        await win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
        if (!process.env.IS_TEST) win.webContents.openDevTools()
    }
    else {
        createProtocol('app')
        // Load the index.html when not in development
        win.loadURL('app://./index.html')
    }

    return win;
}

app.on('ready', async () => {
    createWindow()
        .then(win => {
            ipcMain.on('close-app', () => {
                win.hide();
            });
            ipcMain.on('min-app', () => {
                win.minimize();
            });
        });
});

index.html

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    </head>
    <body>

        <span role="control-panel">
            <button type="button"
                id="min-app" 
                aria-label="minimize your app">
                <i class="mdi mdi-window-minimize text-2xl"></i>
            </button>

            <button type="button"
                id="close-app"
                aria-label="close your app">
                <i class="mdi mdi-close text-2xl"></i>
            </button>
        </span>

        <script>
            // for close/min app
            const { ipcRenderer } = require('electron');
            document.getElementById('close-app').addEventListener('click', () => {
                ipcRenderer.send('close-app');
            });
            document.getElementById('min-app').addEventListener('click', () => {
                ipcRenderer.send('min-app');
            });
        </script>
    </body>
</html>