You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在关闭Electron应用时原生显示保存更改提示对话框?

实现Electron原生“未保存更改”提示方案

嘿,这个需求我刚好实操过,完全可以用Electron的原生API实现,不用自定义对话框!我给你一步步拆解怎么做,完美适配macOS的原生提示(比如关闭按钮变红点)和跨平台的关闭前确认:

核心思路

我们需要做三件事:

  • 跟踪应用的“未保存更改”状态
  • 在窗口关闭/应用退出时触发原生确认对话框
  • 针对macOS系统,启用原生的未保存状态视觉提示(关闭按钮红点、标题星号)

1. 跟踪未保存状态

首先,在主进程里维护一个状态变量(比如hasUnsavedChanges),当用户修改内容时(比如在渲染进程输入、操作),通过IPC通知主进程更新这个变量。

渲染进程示例(通知状态变化)

// 假设用户在编辑区域输入时触发
document.querySelector('#editor').addEventListener('input', () => {
  // 通知主进程:现在有未保存更改
  window.ipcRenderer.send('update-unsaved-status', true);
});

// 用户点击保存按钮后,通知主进程状态重置
document.querySelector('#save-btn').addEventListener('click', async () => {
  // 执行你的保存逻辑(比如写入文件)
  await saveToFile();
  // 通知主进程:已保存,无未更改内容
  window.ipcRenderer.send('update-unsaved-status', false);
});

2. 主进程处理关闭事件

在主进程中,我们需要监听两个关键事件:窗口的close事件(用户点击关闭按钮)和应用的before-quit事件(用户直接退出应用,比如macOS菜单栏的“退出”),在这两个事件里检查未保存状态,触发原生对话框。

主进程核心代码

const { app, BrowserWindow, dialog } = require('electron');
const path = require('path');
let mainWindow;
let hasUnsavedChanges = false;

function createWindow() {
  mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences: {
      contextIsolation: true,
      preload: path.join(__dirname, 'preload.js') // 用于IPC通信的预加载脚本
    }
  });

  // 监听窗口关闭事件
  mainWindow.on('close', (event) => {
    handleUnsavedChanges(event);
  });

  // 监听应用退出事件(比如用户点击菜单栏的退出)
  app.on('before-quit', (event) => {
    if (hasUnsavedChanges) {
      event.preventDefault();
      // 触发窗口的close事件,复用同一个处理逻辑
      mainWindow.emit('close');
    }
  });

  // 监听渲染进程发来的状态更新
  mainWindow.webContents.on('ipc-message', (_, channel, args) => {
    if (channel === 'update-unsaved-status') {
      hasUnsavedChanges = args;
      // 针对macOS设置原生未保存提示
      if (process.platform === 'darwin') {
        mainWindow.setDocumentEdited(args); // 开启/关闭关闭按钮红点
      }
      // 跨平台:窗口标题加星号标识未保存
      const baseTitle = '我的Electron应用';
      mainWindow.setTitle(args ? `${baseTitle}*` : baseTitle);
    }
  });
}

// 处理未保存更改的核心逻辑
function handleUnsavedChanges(event) {
  if (!hasUnsavedChanges) return;

  // 阻止默认关闭行为
  event.preventDefault();

  // 显示原生系统对话框
  dialog.showMessageBox(mainWindow, {
    type: 'question',
    buttons: ['保存', '不保存', '取消'],
    defaultId: 0, // 默认选中“保存”
    title: '未保存的更改',
    message: '你有未保存的更改,是否要保存后再退出?'
  }).then((result) => {
    switch (result.response) {
      case 0: // 用户选择“保存”
        saveChanges().then(() => {
          hasUnsavedChanges = false;
          mainWindow.close(); // 保存完成后关闭窗口
        });
        break;
      case 1: // 用户选择“不保存”
        hasUnsavedChanges = false;
        mainWindow.close(); // 直接关闭,丢弃更改
        break;
      case 2: // 用户选择“取消”
        // 什么都不做,窗口保持打开
        break;
    }
  });
}

// 示例保存函数(替换成你的实际保存逻辑)
function saveChanges() {
  return new Promise((resolve) => {
    // 这里写你的文件写入逻辑
    console.log('正在保存更改到文件...');
    setTimeout(resolve, 600); // 模拟异步保存过程
  });
}

// 常规Electron应用生命周期代码
app.whenReady().then(createWindow);

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') app.quit();
});

app.on('activate', () => {
  if (BrowserWindow.getAllWindows().length === 0) createWindow();
});

3. 关键原生特性说明

  • macOS专属:setDocumentEdited(true)
    调用这个API后,macOS系统会自动把窗口的红色关闭按钮变成带小点的样式,这就是你要的原生未保存提示效果,完全符合系统交互规范。
  • 跨平台标题星号
    在窗口标题后加*是跨平台通用的未保存标识,Windows和Linux用户也能快速识别。
  • 原生对话框
    dialog.showMessageBox()调用的是系统原生的对话框组件,风格和系统完全一致,比自定义对话框更符合用户习惯。

内容的提问来源于stack exchange,提问作者David Cruz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:59:12