一、功能全景图
javascript
┌─────────────────────────────────────────────────────────────────────────────┐
│ Electron 原生能力调用架构 │
├─────────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ Electron App │ │
│ ├─────────────────────────┬─────────────────────────┬─────────────────┤ │
│ │ 剪贴板 Clipboard │ 通知 Notification │ 开机自启 │ │
│ ├─────────────────────────┼─────────────────────────┼─────────────────┤ │
│ │ • 读写纯文本 │ • 系统通知弹窗 │ • 登录项设置 │ │
│ │ • 读写 HTML │ • 带图标通知 │ • 隐藏启动 │ │
│ │ • 读写图片 │ • 带操作按钮 │ • 多平台兼容 │ │
│ │ • 读写 RTF │ • 点击回调 │ • 状态查询 │ │
│ │ • 监听剪贴板变化 │ • 关闭回调 │ • 自定义参数 │ │
│ └─────────────────────────┴─────────────────────────┴─────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────────────────────────────────────┐ │
│ │ 操作系统底层 API │ │
│ │ Windows │ macOS │ Linux │ │
│ └─────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────┘
二、剪贴板操作
2.1 基础使用
Electron 的 clipboard 模块提供剪贴板读写能力,可在主进程和渲染进程中使用。
javascript
// main.ts 或 preload.ts
import { clipboard, nativeImage } from 'electron'
// ==================== 文本操作 ====================
// 写入纯文本
clipboard.writeText('Hello Electron!')
// 读取纯文本
const text = clipboard.readText()
console.log('剪贴板内容:', text)
// ==================== HTML 操作 ====================
// 写入 HTML
clipboard.writeHTML('<h1>标题</h1><p>段落内容</p>')
// 读取 HTML
const html = clipboard.readHTML()
console.log('HTML 内容:', html)
// ==================== 图片操作 ====================
// 写入图片
const image = nativeImage.createFromPath('/path/to/image.png')
clipboard.writeImage(image)
// 读取图片
const clipboardImage = clipboard.readImage()
if (!clipboardImage.isEmpty()) {
const imagePath = clipboardImage.toDataURL()
// 使用图片...
}
// ==================== RTF 富文本 ====================
// 写入 RTF
clipboard.writeRTF('{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard This is some {\\b bold} text.\\par}')
// 读取 RTF
const rtf = clipboard.readRTF()
// ==================== 多种格式同时写入 ====================
// 同时写入多种格式
clipboard.write({
text: 'Plain Text',
html: '<strong>HTML</strong>',
rtf: '{\\rtf1\\ansi\\b Bold\\b0}',
bookmark: 'Bookmark Name',
image: nativeImage.createFromPath('/path/to/icon.png')
})
// ==================== 读取可用格式 ====================
// 获取剪贴板中可用的格式列表
const availableFormats = clipboard.availableFormats()
console.log('可用格式:', availableFormats)
// 检查是否有特定格式
const hasText = clipboard.has('text/plain')
const hasImage = clipboard.has('image/png')
2.2 监听剪贴板变化
javascript
// main.ts
import { clipboard, BrowserWindow } from 'electron'
class ClipboardMonitor {
private lastText: string = ''
private intervalId: NodeJS.Timeout | null = null
private window: BrowserWindow | null = null
constructor(window: BrowserWindow) {
this.window = window
}
// 开始监听剪贴板变化
startMonitoring(interval: number = 500) {
this.lastText = clipboard.readText()
this.intervalId = setInterval(() => {
const currentText = clipboard.readText()
if (currentText !== this.lastText) {
this.lastText = currentText
this.onClipboardChange(currentText)
}
}, interval)
}
// 剪贴板变化回调
private onClipboardChange(content: string) {
console.log('剪贴板内容已变化:', content)
// 通知渲染进程
this.window?.webContents.send('clipboard-changed', {
content,
timestamp: Date.now()
})
}
// 停止监听
stopMonitoring() {
if (this.intervalId) {
clearInterval(this.intervalId)
this.intervalId = null
}
}
}
// 使用示例
app.whenReady().then(() => {
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadFile('index.html')
const monitor = new ClipboardMonitor(win)
monitor.startMonitoring()
})
2.3 封装剪贴板工具类
javascript
// utils/clipboard.ts
import { clipboard, nativeImage } from 'electron'
export class ClipboardManager {
/**
* 复制文本
*/
static copyText(text: string): void {
clipboard.writeText(text)
console.log(`已复制文本: ${text.substring(0, 50)}`)
}
/**
* 复制 HTML
*/
static copyHtml(html: string, text?: string): void {
clipboard.write({
html: html,
text: text || this.stripHtml(html)
})
}
/**
* 复制图片
*/
static copyImage(imagePath: string): boolean {
try {
const image = nativeImage.createFromPath(imagePath)
if (!image.isEmpty()) {
clipboard.writeImage(image)
return true
}
return false
} catch (error) {
console.error('复制图片失败:', error)
return false
}
}
/**
* 复制多格式内容(同时支持文本和HTML)
*/
static copyRichContent(plainText: string, htmlText: string): void {
clipboard.write({
text: plainText,
html: htmlText
})
}
/**
* 获取剪贴板文本
*/
static pasteText(): string {
return clipboard.readText()
}
/**
* 获取剪贴板图片(如果存在)
*/
static pasteImage(): string | null {
const image = clipboard.readImage()
if (!image.isEmpty()) {
return image.toDataURL()
}
return null
}
/**
* 清空剪贴板
*/
static clear(): void {
clipboard.clear()
}
/**
* HTML 转纯文本
*/
private static stripHtml(html: string): string {
return html.replace(/<[^>]*>/g, '').replace(/ /g, ' ')
}
}
三、通知功能
3.1 基础通知
Electron 的 Notification 模块用于发送系统通知。
javascript
// main.ts
import { Notification } from 'electron'
// ==================== 基础通知 ====================
function sendBasicNotification() {
const notification = new Notification({
title: '任务完成',
body: '文件导出已完成,点击查看',
silent: false
})
notification.show()
}
// ==================== 带图标的通知 ====================
function sendNotificationWithIcon() {
const notification = new Notification({
title: '新消息',
subtitle: '来自张三', // macOS only
body: '您收到一条新消息,请及时查看',
icon: '/path/to/icon.png', // 图标路径
silent: false,
sound: 'default' // macOS only
})
notification.show()
}
// ==================== 带操作按钮的通知 (macOS) ====================
function sendNotificationWithActions() {
const notification = new Notification({
title: '会议提醒',
subtitle: '团队会议',
body: '10分钟后开始,是否参加?',
actions: [
{ text: '参加', type: 'button' },
{ text: '拒绝', type: 'button' }
],
hasReply: true,
replyPlaceholder: '输入回复内容'
})
// 监听按钮点击
notification.on('action', (event, index) => {
if (index === 0) {
console.log('用户点击了参加')
} else if (index === 1) {
console.log('用户点击了拒绝')
}
})
// 监听回复
notification.on('reply', (event, reply) => {
console.log('用户回复:', reply)
})
notification.show()
}
// ==================== 带超时类型的通知 ====================
function sendPersistentNotification() {
const notification = new Notification({
title: '系统更新',
body: '更新将在重启后生效',
timeoutType: 'never', // 'default' | 'never' - Windows/Linux
urgency: 'critical' // 'normal' | 'critical' | 'low' - Linux
})
notification.show()
}
3.2 通知事件监听
TypeScript
// main.ts
import { Notification } from 'electron'
function createNotificationWithEvents() {
const notification = new Notification({
title: '下载完成',
body: '文件已下载到桌面',
silent: false
})
// 点击通知
notification.on('click', (event) => {
console.log('通知被点击')
// 打开文件或聚焦应用
BrowserWindow.getFocusedWindow()?.show()
})
// 关闭通知
notification.on('close', (event) => {
console.log('通知已关闭')
})
// 显示通知
notification.show()
return notification
}
3.3 通知管理器封装
TypeScript
// utils/notification.ts
import { Notification } from 'electron'
interface NotificationOptions {
title: string
body: string
subtitle?: string
icon?: string
silent?: boolean
actions?: Array<{ text: string; type: 'button' }>
onClick?: () => void
onClose?: () => void
}
export class NotificationManager {
private static instance: NotificationManager
private notifications: Map<string, Notification> = new Map()
static getInstance(): NotificationManager {
if (!NotificationManager.instance) {
NotificationManager.instance = new NotificationManager()
}
return NotificationManager.instance
}
/**
* 发送普通通知
*/
send(options: NotificationOptions): string {
const id = Date.now().toString()
const notification = new Notification({
title: options.title,
subtitle: options.subtitle,
body: options.body,
icon: options.icon,
silent: options.silent ?? false,
actions: options.actions
})
// 绑定事件
if (options.onClick) {
notification.on('click', options.onClick)
}
if (options.onClose) {
notification.on('close', options.onClose)
}
notification.show()
this.notifications.set(id, notification)
// 自动清理
setTimeout(() => {
this.notifications.delete(id)
}, 5000)
return id
}
/**
* 发送成功通知
*/
success(title: string, body: string, onClick?: () => void): void {
this.send({
title: `✅ ${title}`,
body,
icon: '/path/to/success-icon.png',
onClick
})
}
/**
* 发送错误通知
*/
error(title: string, body: string, onClick?: () => void): void {
this.send({
title: `❌ ${title}`,
body,
icon: '/path/to/error-icon.png',
onClick
})
}
/**
* 发送警告通知
*/
warning(title: string, body: string, onClick?: () => void): void {
this.send({
title: `⚠️ ${title}`,
body,
icon: '/path/to/warning-icon.png',
onClick
})
}
/**
* 发送信息通知
*/
info(title: string, body: string, onClick?: () => void): void {
this.send({
title: `ℹ️ ${title}`,
body,
onClick
})
}
}
// 使用示例
const notifier = NotificationManager.getInstance()
notifier.success('操作成功', '文件已保存')
notifier.error('操作失败', '请检查网络连接')
四、开机自启动
4.1 使用 Electron 原生 API
Electron 提供了 app.setLoginItemSettings 方法来设置开机自启动。
javascript
// main.ts
import { app } from 'electron'
// ==================== 基础设置 ====================
// 启用开机自启动
function enableAutoStart() {
app.setLoginItemSettings({
openAtLogin: true
})
console.log('开机自启动已启用')
}
// 禁用开机自启动
function disableAutoStart() {
app.setLoginItemSettings({
openAtLogin: false
})
console.log('开机自启动已禁用')
}
// 查询当前状态
function getAutoStartStatus() {
const settings = app.getLoginItemSettings()
console.log('开机自启动状态:', settings.openAtLogin)
console.log('是否隐藏启动:', settings.wasOpenedAsHidden)
return settings
}
// ==================== 隐藏窗口启动 ====================
// 设置开机隐藏启动(启动后窗口不显示)
function enableAutoStartHidden() {
app.setLoginItemSettings({
openAtLogin: true,
openAsHidden: true // macOS only,启动时隐藏窗口
})
}
// ==================== 自定义参数启动 ====================
// 带参数启动,用于区分启动方式
function enableAutoStartWithArgs() {
app.setLoginItemSettings({
openAtLogin: true,
args: ['--openAsHidden', '--silent-start'] // 自定义启动参数
})
}
// 在主进程中检测启动参数
function checkStartupArgs() {
const args = process.argv
if (args.includes('--openAsHidden')) {
console.log('应用通过开机自启动启动,将隐藏窗口')
// 不显示主窗口
return true
}
console.log('应用通过用户手动启动')
return false
}
// ==================== Windows 注册表名称自定义 ====================
// Windows 下可自定义注册表项名称
function enableAutoStartWithCustomName() {
app.setLoginItemSettings({
openAtLogin: true,
name: 'MyAppName', // 自定义注册表键名
enabled: true
})
}
4.2 完整开机自启动管理类
javascript
// utils/autoLaunch.ts
import { app } from 'electron'
export interface AutoStartConfig {
enabled: boolean
hidden?: boolean
args?: string[]
}
export class AutoLaunchManager {
private static instance: AutoLaunchManager
static getInstance(): AutoLaunchManager {
if (!AutoLaunchManager.instance) {
AutoLaunchManager.instance = new AutoLaunchManager()
}
return AutoLaunchManager.instance
}
/**
* 启用开机自启动
*/
enable(hidden: boolean = false, customArgs?: string[]): void {
try {
app.setLoginItemSettings({
openAtLogin: true,
openAsHidden: hidden,
args: customArgs || this.getDefaultArgs(hidden)
})
console.log('✅ 开机自启动已启用', hidden ? '(隐藏启动)' : '')
} catch (error) {
console.error('启用开机自启动失败:', error)
}
}
/**
* 禁用开机自启动
*/
disable(): void {
try {
app.setLoginItemSettings({
openAtLogin: false
})
console.log('❌ 开机自启动已禁用')
} catch (error) {
console.error('禁用开机自启动失败:', error)
}
}
/**
* 获取当前状态
*/
getStatus(): {
enabled: boolean
wasOpenedAsHidden: boolean
isHiddenStart: boolean
} {
const settings = app.getLoginItemSettings()
const args = process.argv
return {
enabled: settings.openAtLogin,
wasOpenedAsHidden: settings.wasOpenedAsHidden,
isHiddenStart: args.includes('--openAsHidden')
}
}
/**
* 切换状态
*/
toggle(hidden: boolean = false): boolean {
const current = this.getStatus()
if (current.enabled) {
this.disable()
return false
} else {
this.enable(hidden)
return true
}
}
/**
* 检查是否通过开机自启动启动
*/
isLaunchedByAutoStart(): boolean {
const settings = app.getLoginItemSettings()
const args = process.argv
// macOS 使用 wasOpenedAsHidden
if (process.platform === 'darwin') {
return settings.wasOpenedAsHidden
}
// Windows/Linux 使用自定义参数
return args.includes('--openAsHidden')
}
/**
* 处理开机启动时的行为
*/
handleAutoStartLaunch(mainWindow: Electron.BrowserWindow | null): void {
if (this.isLaunchedByAutoStart()) {
console.log('应用通过开机自启动启动,窗口将保持隐藏')
// 可以选择不显示窗口,或显示到系统托盘
// mainWindow?.hide()
} else {
console.log('应用通过用户手动启动,正常显示窗口')
mainWindow?.show()
}
}
private getDefaultArgs(hidden: boolean): string[] {
return hidden ? ['--openAsHidden'] : []
}
}
4.3 使用 auto-launch 第三方库
除了原生 API,也可以使用 auto-launch 库。
javascript
npm install auto-launch --save
javascript
// 使用 auto-launch 库
import AutoLaunch from 'auto-launch'
const appLauncher = new AutoLaunch({
name: 'MyElectronApp',
path: app.getPath('exe'), // 可选,指定可执行文件路径
isHidden: false // 是否隐藏启动
})
// 启用
async function enableAutoLaunch() {
try {
await appLauncher.enable()
console.log('开机自启动已启用')
} catch (err) {
console.error('启用失败:', err)
}
}
// 禁用
async function disableAutoLaunch() {
try {
await appLauncher.disable()
console.log('开机自启动已禁用')
} catch (err) {
console.error('禁用失败:', err)
}
}
// 检查状态
async function isAutoLaunchEnabled() {
try {
const enabled = await appLauncher.isEnabled()
console.log('自启动状态:', enabled)
return enabled
} catch (err) {
console.error('检查失败:', err)
return false
}
}
4.4 Windows Store 应用特殊处理
对于 Windows Store 应用,需要使用专门的模块。
javascript
npm install electron-winstore-auto-launch
TypeScript
// 需要在 appxmanifest.xml 中配置 Extension
// <desktop:Extension Category="windows.startupTask" ...>
import { WindowsStoreAutoLaunch } from 'electron-winstore-auto-launch'
// 启用
await WindowsStoreAutoLaunch.enable()
// 禁用
await WindowsStoreAutoLaunch.disable()
// 获取状态
const status = await WindowsStoreAutoLaunch.getStatus()
// 0: disabled, 1: disabledByUser, 2: enabled
五、渲染进程调用封装
5.1 Preload 脚本
javascript
// preload.ts
import { contextBridge, ipcRenderer, clipboard } from 'electron'
// 暴露安全的 API 给渲染进程
contextBridge.exposeInMainWorld('electronAPI', {
// ==================== 剪贴板 ====================
clipboard: {
writeText: (text: string) => clipboard.writeText(text),
readText: () => clipboard.readText(),
writeHtml: (html: string) => clipboard.writeHTML(html),
readHtml: () => clipboard.readHTML(),
copyImage: (imagePath: string) => {
const { nativeImage } = require('electron')
const image = nativeImage.createFromPath(imagePath)
clipboard.writeImage(image)
return !image.isEmpty()
}
},
// ==================== 通知 ====================
notification: {
send: (options: { title: string; body: string; icon?: string }) => {
ipcRenderer.send('send-notification', options)
}
},
// ==================== 开机自启 ====================
autoLaunch: {
enable: (hidden?: boolean) => ipcRenderer.invoke('auto-launch-enable', hidden),
disable: () => ipcRenderer.invoke('auto-launch-disable'),
getStatus: () => ipcRenderer.invoke('auto-launch-status'),
toggle: (hidden?: boolean) => ipcRenderer.invoke('auto-launch-toggle', hidden)
},
// ==================== 事件监听 ====================
onClipboardChange: (callback: (content: string) => void) => {
ipcRenderer.on('clipboard-changed', (_, data) => callback(data))
}
})
5.2 主进程 IPC 处理
javascript
// main.ts
import { ipcMain, Notification, app, BrowserWindow } from 'electron'
import { AutoLaunchManager } from './utils/autoLaunch'
import { NotificationManager } from './utils/notification'
// 通知 IPC
ipcMain.on('send-notification', (event, options) => {
const notifier = NotificationManager.getInstance()
notifier.send(options)
})
// 开机自启 IPC
ipcMain.handle('auto-launch-enable', async (event, hidden) => {
const manager = AutoLaunchManager.getInstance()
manager.enable(hidden)
return manager.getStatus()
})
ipcMain.handle('auto-launch-disable', async () => {
const manager = AutoLaunchManager.getInstance()
manager.disable()
return manager.getStatus()
})
ipcMain.handle('auto-launch-status', async () => {
const manager = AutoLaunchManager.getInstance()
return manager.getStatus()
})
ipcMain.handle('auto-launch-toggle', async (event, hidden) => {
const manager = AutoLaunchManager.getInstance()
const newStatus = manager.toggle(hidden)
return newStatus
})
5.3 Vue3 组合式函数
javascript
// composables/useElectron.ts
import { ref } from 'vue'
declare global {
interface Window {
electronAPI: {
clipboard: {
writeText: (text: string) => void
readText: () => string
writeHtml: (html: string) => void
readHtml: () => string
copyImage: (path: string) => boolean
}
notification: {
send: (options: { title: string; body: string; icon?: string }) => void
}
autoLaunch: {
enable: (hidden?: boolean) => Promise<{ enabled: boolean }>
disable: () => Promise<{ enabled: boolean }>
getStatus: () => Promise<{ enabled: boolean; isHiddenStart: boolean }>
toggle: (hidden?: boolean) => Promise<boolean>
}
onClipboardChange: (callback: (content: string) => void) => void
}
}
}
export function useElectron() {
const isElectron = ref(!!window.electronAPI)
/**
* 复制文本
*/
const copyToClipboard = (text: string): boolean => {
if (!isElectron.value) {
// 降级到 Web API
navigator.clipboard.writeText(text)
return true
}
window.electronAPI.clipboard.writeText(text)
return true
}
/**
* 粘贴文本
*/
const pasteFromClipboard = (): string => {
if (!isElectron.value) {
return ''
}
return window.electronAPI.clipboard.readText()
}
/**
* 发送通知
*/
const sendNotification = (title: string, body: string, icon?: string) => {
if (!isElectron.value) {
// 降级到 Web Notification
if ('Notification' in window) {
new Notification(title, { body, icon })
}
return
}
window.electronAPI.notification.send({ title, body, icon })
}
/**
* 启用开机自启
*/
const enableAutoStart = async (hidden: boolean = false) => {
if (!isElectron.value) return false
const result = await window.electronAPI.autoLaunch.enable(hidden)
return result.enabled
}
/**
* 禁用开机自启
*/
const disableAutoStart = async () => {
if (!isElectron.value) return false
const result = await window.electronAPI.autoLaunch.disable()
return !result.enabled
}
/**
* 获取开机自启状态
*/
const getAutoStartStatus = async () => {
if (!isElectron.value) return { enabled: false, isHiddenStart: false }
return await window.electronAPI.autoLaunch.getStatus()
}
/**
* 切换开机自启
*/
const toggleAutoStart = async (hidden: boolean = false) => {
if (!isElectron.value) return false
return await window.electronAPI.autoLaunch.toggle(hidden)
}
/**
* 监听剪贴板变化
*/
const onClipboardChange = (callback: (content: string) => void) => {
if (!isElectron.value) return
window.electronAPI.onClipboardChange(callback)
}
return {
isElectron,
copyToClipboard,
pasteFromClipboard,
sendNotification,
enableAutoStart,
disableAutoStart,
getAutoStartStatus,
toggleAutoStart,
onClipboardChange
}
}
5.4 Vue3 组件使用示例
javascript
<template>
<div class="electron-demo">
<h2>Electron 原生能力演示</h2>
<!-- 剪贴板 -->
<div class="section">
<h3>📋 剪贴板</h3>
<textarea v-model="clipboardText" placeholder="输入要复制的内容"></textarea>
<button @click="handleCopy">复制到剪贴板</button>
<button @click="handlePaste">粘贴</button>
<div v-if="pastedText" class="result">
粘贴内容: {{ pastedText }}
</div>
</div>
<!-- 通知 -->
<div class="section">
<h3>🔔 系统通知</h3>
<input v-model="notificationTitle" placeholder="通知标题" />
<input v-model="notificationBody" placeholder="通知内容" />
<button @click="handleNotify">发送通知</button>
</div>
<!-- 开机自启 -->
<div class="section">
<h3>🚀 开机自启动</h3>
<div class="status">
当前状态:
<span :class="autoStartStatus ? 'enabled' : 'disabled'">
{{ autoStartStatus ? '已启用' : '已禁用' }}
</span>
</div>
<button @click="handleToggleAutoStart">
{{ autoStartStatus ? '禁用' : '启用' }}
</button>
<label v-if="autoStartStatus">
<input type="checkbox" v-model="autoStartHidden" />
隐藏窗口启动
</label>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { useElectron } from '@/composables/useElectron'
const {
copyToClipboard,
pasteFromClipboard,
sendNotification,
getAutoStartStatus,
toggleAutoStart,
onClipboardChange
} = useElectron()
// 剪贴板
const clipboardText = ref('')
const pastedText = ref('')
const handleCopy = () => {
copyToClipboard(clipboardText.value)
sendNotification('复制成功', '内容已复制到剪贴板')
}
const handlePaste = () => {
pastedText.value = pasteFromClipboard()
}
// 通知
const notificationTitle = ref('系统提示')
const notificationBody = ref('这是一条测试通知')
const handleNotify = () => {
sendNotification(notificationTitle.value, notificationBody.value)
}
// 开机自启
const autoStartStatus = ref(false)
const autoStartHidden = ref(false)
const loadAutoStartStatus = async () => {
const status = await getAutoStartStatus()
autoStartStatus.value = status.enabled
}
const handleToggleAutoStart = async () => {
const newStatus = await toggleAutoStart(autoStartHidden.value)
autoStartStatus.value = newStatus
}
// 监听剪贴板变化
onMounted(() => {
loadAutoStartStatus()
onClipboardChange((content) => {
console.log('剪贴板内容变化:', content)
sendNotification('剪贴板更新', '检测到新的剪贴板内容')
})
})
</script>
<style scoped>
.electron-demo {
padding: 20px;
font-family: sans-serif;
}
.section {
margin-bottom: 24px;
padding: 16px;
border: 1px solid #ddd;
border-radius: 8px;
}
button {
margin: 8px 8px 8px 0;
padding: 8px 16px;
background: #42b883;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.enabled {
color: #42b883;
}
.disabled {
color: #ff6b6b;
}
</style>
六、注意事项与最佳实践
6.1 跨平台差异
| 功能 | Windows | macOS | Linux |
|---|---|---|---|
openAsHidden |
不支持 | 支持 | 不支持 |
sound 属性 |
部分支持 | 支持 | 部分支持 |
actions 按钮 |
不支持 | 支持 | 不支持 |
urgency 级别 |
不支持 | 不支持 | 支持 |
6.2 权限说明
javascript
// macOS 通知需要请求权限
if (process.platform === 'darwin') {
app.requestSingleInstanceLock()
// 通知权限在首次使用时自动请求
}
// Windows 开机自启可能需要管理员权限
// 建议在安装包中配置
6.3 内存管理
javascript
// 及时清理不需要的通知
const notification = new Notification({...})
notification.show()
// 组件销毁时移除事件监听
notification.removeAllListeners()