跳到主要内容

剪贴板与通知

剪贴板和系统通知是桌面应用常用的系统集成功能。本节介绍如何使用 Electron 的 clipboardNotification 模块。

剪贴板

clipboard 模块提供了读写系统剪贴板的能力。

写入剪贴板

const { clipboard } = require('electron')

clipboard.writeText('要复制的文本')

读取剪贴板

const text = clipboard.readText()
console.log('剪贴板内容:', text)

写入 HTML

clipboard.writeHTML('<b>加粗文本</b>')
const html = clipboard.readHTML()

写入图片

const { clipboard, nativeImage } = require('electron')

const image = nativeImage.createFromPath('/path/to/image.png')
clipboard.writeImage(image)

const clipImage = clipboard.readImage()

写入多格式

clipboard.write({
text: '纯文本',
html: '<b>HTML 文本</b>',
image: nativeImage.createFromPath('/path/to/image.png')
})

清空剪贴板

clipboard.clear()

检查格式

clipboard.has('text')
clipboard.has('image')
clipboard.has('html')

可用格式

const formats = clipboard.availableFormats()
console.log('可用格式:', formats)

系统通知

Notification 模块用于显示系统通知。

基本用法

const { Notification } = require('electron')

const notification = new Notification({
title: '通知标题',
body: '通知内容',
icon: '/path/to/icon.png'
})

notification.show()

通知事件

const notification = new Notification({
title: '新消息',
body: '您有一条新消息'
})

notification.on('show', () => {
console.log('通知已显示')
})

notification.on('click', () => {
console.log('通知被点击')
mainWindow.show()
})

notification.on('close', () => {
console.log('通知已关闭')
})

notification.on('action', (event, index) => {
console.log('点击了操作:', index)
})

notification.show()

通知选项

const notification = new Notification({
title: '通知标题',
subtitle: '副标题',
body: '通知正文内容',
silent: false,
icon: '/path/to/icon.png',
hasReply: true,
replyPlaceholder: '输入回复...',
actions: [
{ type: 'button', text: '确认' },
{ type: 'button', text: '取消' }
],
closeButtonText: '关闭'
})

选项说明

选项类型说明
titleString通知标题
subtitleString副标题
bodyString通知正文
silentBoolean是否静音
iconString/NativeImage通知图标
hasReplyBoolean是否显示回复框
replyPlaceholderString回复框占位符
actionsArray操作按钮
closeButtonTextString关闭按钮文本

检查通知支持

if (Notification.isSupported()) {
const notification = new Notification({...})
notification.show()
} else {
console.log('系统不支持通知')
}

关闭通知

const notification = new Notification({...})
notification.show()

setTimeout(() => {
notification.close()
}, 5000)

在渲染进程中使用

剪贴板

预加载脚本

const { contextBridge, clipboard } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
writeText: (text) => clipboard.writeText(text),
readText: () => clipboard.readText()
})

渲染进程

document.getElementById('copy').addEventListener('click', () => {
const text = document.getElementById('text').value
window.electronAPI.writeText(text)
})

document.getElementById('paste').addEventListener('click', () => {
const text = window.electronAPI.readText()
document.getElementById('output').value = text
})

通知

主进程

const { ipcMain, Notification } = require('electron')

ipcMain.handle('notification:show', (event, options) => {
const notification = new Notification(options)

notification.on('click', () => {
event.sender.send('notification:clicked')
})

notification.show()
return true
})

预加载脚本

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
showNotification: (options) => ipcRenderer.invoke('notification:show', options),
onNotificationClicked: (callback) => ipcRenderer.on('notification:clicked', callback)
})

渲染进程

document.getElementById('notify').addEventListener('click', async () => {
await window.electronAPI.showNotification({
title: '提示',
body: '操作已完成'
})
})

window.electronAPI.onNotificationClicked(() => {
console.log('通知被点击')
})

完整示例

main.js

const { app, BrowserWindow, clipboard, Notification, ipcMain, nativeImage } = require('electron')
const path = require('node:path')

function createWindow() {
const mainWindow = new BrowserWindow({
width: 600,
height: 400,
webPreferences: {
preload: path.join(__dirname, 'preload.js')
}
})

mainWindow.loadFile('index.html')
}

ipcMain.handle('clipboard:writeText', (event, text) => {
clipboard.writeText(text)
return true
})

ipcMain.handle('clipboard:readText', () => {
return clipboard.readText()
})

ipcMain.handle('clipboard:writeImage', (event, imagePath) => {
const image = nativeImage.createFromPath(imagePath)
clipboard.writeImage(image)
return true
})

ipcMain.handle('notification:show', (event, options) => {
if (!Notification.isSupported()) {
return { success: false, error: '不支持通知' }
}

const notification = new Notification({
title: options.title,
body: options.body,
icon: options.icon ? nativeImage.createFromPath(options.icon) : undefined,
silent: options.silent || false
})

notification.on('click', () => {
event.sender.send('notification:clicked')
})

notification.show()
return { success: true }
})

app.whenReady().then(createWindow)

preload.js

const { contextBridge, ipcRenderer } = require('electron')

contextBridge.exposeInMainWorld('electronAPI', {
writeText: (text) => ipcRenderer.invoke('clipboard:writeText', text),
readText: () => ipcRenderer.invoke('clipboard:readText'),
writeImage: (path) => ipcRenderer.invoke('clipboard:writeImage', path),
showNotification: (options) => ipcRenderer.invoke('notification:show', options),
onNotificationClicked: (callback) => {
ipcRenderer.on('notification:clicked', callback)
}
})

index.html

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>剪贴板与通知示例</title>
<style>
body { font-family: sans-serif; padding: 20px; }
.section { margin-bottom: 20px; }
input, textarea { width: 100%; padding: 8px; margin: 5px 0; box-sizing: border-box; }
button { padding: 10px 20px; margin: 5px; cursor: pointer; }
</style>
</head>
<body>
<div class="section">
<h2>剪贴板操作</h2>
<textarea id="text-input" rows="3" placeholder="输入要复制的文本"></textarea>
<button id="copy-btn">复制到剪贴板</button>
<button id="paste-btn">从剪贴板粘贴</button>
<textarea id="output" rows="3" placeholder="粘贴的内容会显示在这里" readonly></textarea>
</div>

<div class="section">
<h2>系统通知</h2>
<input id="notification-title" placeholder="通知标题" value="提示">
<input id="notification-body" placeholder="通知内容" value="操作已完成">
<button id="notify-btn">发送通知</button>
</div>

<script>
document.getElementById('copy-btn').addEventListener('click', async () => {
const text = document.getElementById('text-input').value
await window.electronAPI.writeText(text)
alert('已复制到剪贴板')
})

document.getElementById('paste-btn').addEventListener('click', async () => {
const text = await window.electronAPI.readText()
document.getElementById('output').value = text
})

document.getElementById('notify-btn').addEventListener('click', async () => {
const title = document.getElementById('notification-title').value
const body = document.getElementById('notification-body').value

const result = await window.electronAPI.showNotification({ title, body })
if (!result.success) {
alert('发送通知失败: ' + result.error)
}
})

window.electronAPI.onNotificationClicked(() => {
console.log('通知被点击')
})
</script>
</body>
</html>

平台差异

剪贴板

  • Windows:支持所有格式
  • macOS:支持所有格式,还有 findText 等额外方法
  • Linux:需要图形环境支持

通知

  • Windows:支持操作按钮和回复
  • macOS:支持副标题、回复框、操作按钮
  • Linux:依赖桌面环境的通知服务

最佳实践

剪贴板

  1. 检查内容是否存在
if (clipboard.has('text')) {
const text = clipboard.readText()
}
  1. 处理大文件

剪贴板不适合存储大量数据,大文件应该使用文件路径。

通知

  1. 检查支持
if (!Notification.isSupported()) {
console.log('系统不支持通知')
return
}
  1. 合理使用

不要频繁发送通知,避免打扰用户。

  1. 处理点击事件

通知被点击时,通常应该激活应用窗口:

notification.on('click', () => {
mainWindow.show()
mainWindow.focus()
})

总结

剪贴板和通知是桌面应用常用的系统集成功能:

  1. clipboard 模块提供剪贴板读写能力
  2. Notification 模块用于显示系统通知
  3. 通过 IPC 让渲染进程也能使用这些功能
  4. 注意平台差异,做好兼容处理