对话框与通知 #
一、原生对话框 #
1.1 dialog 模块 #
javascript
const { dialog } = require('electron');
1.2 消息对话框 #
javascript
// 基本消息对话框
dialog.showMessageBox(mainWindow, {
type: 'info',
title: '提示',
message: '操作已完成',
buttons: ['确定']
});
// 带选项的消息对话框
const result = await dialog.showMessageBox(mainWindow, {
type: 'question',
title: '确认删除',
message: '确定要删除这个文件吗?',
detail: '此操作无法撤销',
buttons: ['删除', '取消'],
defaultId: 1, // 默认选中第二个按钮
cancelId: 1, // ESC 键对应的按钮
checkboxLabel: '不再询问',
checkboxChecked: false,
icon: nativeImage.createFromPath('warning.png')
});
console.log('用户选择:', result.response); // 按钮索引
console.log('复选框状态:', result.checkboxChecked);
1.3 消息类型 #
| 类型 | 图标 | 用途 |
|---|---|---|
| none | 无 | 普通消息 |
| info | 信息图标 | 信息提示 |
| error | 错误图标 | 错误提示 |
| question | 问号图标 | 询问确认 |
| warning | 警告图标 | 警告提示 |
1.4 文件选择对话框 #
javascript
// 打开文件
const result = await dialog.showOpenDialog(mainWindow, {
title: '选择文件',
defaultPath: app.getPath('documents'),
buttonLabel: '选择',
filters: [
{ name: '文本文件', extensions: ['txt', 'md'] },
{ name: '图片', extensions: ['jpg', 'png', 'gif'] },
{ name: '所有文件', extensions: ['*'] }
],
properties: [
'openFile', // 选择文件
'openDirectory', // 选择目录
'multiSelections', // 多选
'showHiddenFiles', // 显示隐藏文件
'createDirectory' // 允许创建目录
]
});
if (!result.canceled) {
console.log('选择的文件:', result.filePaths);
}
1.5 保存对话框 #
javascript
const result = await dialog.showSaveDialog(mainWindow, {
title: '保存文件',
defaultPath: path.join(app.getPath('documents'), 'untitled.txt'),
buttonLabel: '保存',
filters: [
{ name: '文本文件', extensions: ['txt'] },
{ name: '所有文件', extensions: ['*'] }
],
properties: [
'createDirectory',
'showOverwriteConfirmation'
]
});
if (!result.canceled) {
console.log('保存路径:', result.filePath);
// 执行保存操作
fs.writeFileSync(result.filePath, content);
}
1.6 错误对话框 #
javascript
// 显示错误对话框(不需要父窗口)
dialog.showErrorBox('错误标题', '错误详细信息');
// 更详细的错误对话框
await dialog.showMessageBox(mainWindow, {
type: 'error',
title: '错误',
message: '操作失败',
detail: '无法连接到服务器,请检查网络连接。'
});
二、系统通知 #
2.1 基本通知 #
javascript
const { Notification } = require('electron');
// 检查是否支持通知
if (Notification.isSupported()) {
const notification = new Notification({
title: '通知标题',
body: '通知内容',
icon: path.join(__dirname, 'icon.png'),
silent: false // 是否静音
});
notification.on('click', () => {
console.log('通知被点击');
mainWindow.show();
});
notification.on('close', () => {
console.log('通知被关闭');
});
notification.show();
}
2.2 通知选项 #
javascript
const notification = new Notification({
title: '新消息',
body: '您有一条新消息',
subtitle: '副标题', // macOS
icon: 'icon.png',
image: 'preview.png', // Windows 大图
silent: false,
sound: 'default', // macOS
urgency: 'normal', // Linux: normal, low, critical
closeButtonText: '关闭', // macOS
actions: [
{
type: 'button',
text: '查看'
},
{
type: 'button',
text: '忽略'
}
]
});
notification.on('action', (event, index) => {
console.log('点击了按钮:', index);
});
notification.show();
2.3 通知权限 #
javascript
// 检查权限状态
const permission = Notification.getPermissionLevel();
// 'granted' - 已授权
// 'denied' - 已拒绝
// 'default' - 未询问
// 请求权限(某些平台需要)
// 注意:Electron 中通常默认已授权
2.4 进度通知 #
javascript
// 带进度的通知(Windows)
const notification = new Notification({
title: '下载中',
body: '正在下载文件...',
progress: 50 // 0-100
});
notification.show();
// 更新进度
function updateProgress(percent) {
notification.progress = percent;
notification.show();
}
三、自定义对话框 #
3.1 模态窗口对话框 #
javascript
// 创建自定义对话框窗口
async function showCustomDialog(parent, options) {
return new Promise((resolve) => {
const dialogWin = new BrowserWindow({
width: options.width || 400,
height: options.height || 300,
parent: parent,
modal: true,
show: false,
autoHideMenuBar: true,
resizable: false,
webPreferences: {
preload: path.join(__dirname, 'dialog-preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
dialogWin.loadFile('dialog.html');
dialogWin.once('ready-to-show', () => {
dialogWin.show();
});
// 接收对话框结果
ipcMain.once('dialog-result', (event, result) => {
dialogWin.close();
resolve(result);
});
});
}
// 使用
const result = await showCustomDialog(mainWindow, {
title: '自定义对话框',
width: 500,
height: 400
});
3.2 确认对话框封装 #
javascript
// 封装确认对话框
async function confirm(parent, message, options = {}) {
const result = await dialog.showMessageBox(parent, {
type: 'question',
title: options.title || '确认',
message: message,
buttons: ['确定', '取消'],
defaultId: 0,
cancelId: 1,
...options
});
return result.response === 0;
}
// 使用
if (await confirm(mainWindow, '确定要删除吗?')) {
deleteItem();
}
3.3 输入对话框 #
javascript
// 使用自定义窗口实现输入对话框
async function prompt(parent, title, defaultValue = '') {
return new Promise((resolve) => {
const promptWin = new BrowserWindow({
width: 400,
height: 150,
parent: parent,
modal: true,
show: false,
autoHideMenuBar: true,
resizable: false,
webPreferences: {
preload: path.join(__dirname, 'prompt-preload.js'),
nodeIntegration: false,
contextIsolation: true
}
});
promptWin.loadFile('prompt.html');
promptWin.webContents.on('did-finish-load', () => {
promptWin.webContents.send('init', { title, defaultValue });
promptWin.show();
});
ipcMain.once('prompt-result', (event, value) => {
promptWin.close();
resolve(value);
});
});
}
// 使用
const name = await prompt(mainWindow, '请输入名称:', '默认值');
四、文件拖放 #
4.1 处理文件拖放 #
javascript
// 主进程
mainWindow.webContents.on('did-finish-load', () => {
mainWindow.webContents.send('setup-drag-drop');
});
// 渲染进程
document.addEventListener('DOMContentLoaded', () => {
const dropZone = document.getElementById('drop-zone');
dropZone.addEventListener('dragover', (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.add('drag-over');
});
dropZone.addEventListener('dragleave', (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.remove('drag-over');
});
dropZone.addEventListener('drop', (e) => {
e.preventDefault();
e.stopPropagation();
dropZone.classList.remove('drag-over');
const files = Array.from(e.dataTransfer.files);
console.log('拖放的文件:', files);
// 处理文件
files.forEach(file => {
processFile(file.path);
});
});
});
4.2 拖放文件到应用图标 #
javascript
// macOS: 处理文件拖放到 Dock 图标
app.on('open-file', (event, filePath) => {
event.preventDefault();
console.log('打开文件:', filePath);
if (mainWindow) {
mainWindow.webContents.send('open-file', filePath);
}
});
// Windows/Linux: 从命令行参数获取
if (process.argv.length > 1) {
const filePath = process.argv[1];
console.log('打开文件:', filePath);
}
五、进度反馈 #
5.1 任务栏进度 #
javascript
// Windows 任务栏进度条
mainWindow.setProgressBar(0);
async function downloadFile(url) {
mainWindow.setProgressBar(0);
for (let i = 0; i <= 100; i++) {
await new Promise(r => setTimeout(r, 100));
mainWindow.setProgressBar(i / 100);
}
mainWindow.setProgressBar(-1); // 完成
}
5.2 加载对话框 #
javascript
// 显示加载对话框
async function showLoadingDialog(parent, task, message) {
const loadingWin = new BrowserWindow({
width: 300,
height: 100,
parent: parent,
modal: true,
show: false,
frame: false,
transparent: true,
webPreferences: {
nodeIntegration: false,
contextIsolation: true
}
});
loadingWin.loadFile('loading.html');
loadingWin.webContents.on('did-finish-load', () => {
loadingWin.webContents.send('update-message', message);
loadingWin.show();
});
try {
const result = await task();
return result;
} finally {
loadingWin.close();
}
}
// 使用
const result = await showLoadingDialog(
mainWindow,
() => fetchData(),
'正在加载数据...'
);
六、最佳实践 #
6.1 对话框封装 #
javascript
// dialogs.js
class DialogManager {
constructor() {
this.parentWindow = null;
}
setParent(window) {
this.parentWindow = window;
}
async alert(message, title = '提示') {
await dialog.showMessageBox(this.parentWindow, {
type: 'info',
title,
message
});
}
async confirm(message, title = '确认') {
const result = await dialog.showMessageBox(this.parentWindow, {
type: 'question',
title,
message,
buttons: ['确定', '取消'],
defaultId: 0,
cancelId: 1
});
return result.response === 0;
}
async error(message, title = '错误') {
await dialog.showMessageBox(this.parentWindow, {
type: 'error',
title,
message
});
}
async openFile(options = {}) {
const result = await dialog.showOpenDialog(this.parentWindow, {
properties: ['openFile'],
...options
});
return result.canceled ? null : result.filePaths[0];
}
async saveFile(options = {}) {
const result = await dialog.showSaveDialog(this.parentWindow, options);
return result.canceled ? null : result.filePath;
}
notify(title, body) {
if (Notification.isSupported()) {
new Notification({ title, body }).show();
}
}
}
module.exports = new DialogManager();
6.2 使用封装 #
javascript
// main.js
const dialogs = require('./dialogs');
// 设置父窗口
dialogs.setParent(mainWindow);
// 使用
if (await dialogs.confirm('确定删除?')) {
await deleteItem();
dialogs.notify('成功', '项目已删除');
}
七、总结 #
7.1 核心要点 #
| 要点 | 说明 |
|---|---|
| 消息对话框 | showMessageBox 显示各种类型消息 |
| 文件对话框 | showOpenDialog/showSaveDialog |
| 系统通知 | Notification 类发送通知 |
| 自定义对话框 | 使用 BrowserWindow 实现 |
| 进度反馈 | 任务栏进度条和加载对话框 |
7.2 下一步 #
现在你已经掌握了对话框与通知的使用,接下来让我们学习 快捷键与系统,深入了解全局快捷键和系统集成!
最后更新:2026-03-28