常用的 electronAPI 方法
1 ipcRenderer 方法
ipcRenderer 是最常用的功能,用于渲染进程和主进程之间的通信。
方法 | 用途 |
---|---|
ipcRenderer.send(channel, …args) | 向主进程发送异步消息 |
ipcRenderer.invoke(channel, …args) | 通过异步调用向主进程请求数据,并返回 Promise |
ipcRenderer.on(channel, listener) | 监听主进程发来的消息 |
ipcRenderer.once(channel, listener) | 只监听一次主进程的消息,触发后自动移除监听器 |
ipcRenderer.removeAllListeners(channel) | 移除指定频道的所有监听器 |
React 使用示例
示例一: 通过ipcRenderer.send 实现通信
写了一个按钮,点击发送给主进程,send接收两个参数,第一个是通信通道的名称要和主进程的名称相同,第二个是要传递的数据
const [count, setCount] = useState(0)
const handlesubmit = (): void => {
window.electron.ipcRenderer.send('tong_01', count)
}
在electron的主进程中接收,通过ipcMain.on的方式,这里也是接收两个参数,第一个是通信名称,第二个回调函数,回调函数的参数第一个是事件,第二个就是渲染进程传递而来的数据,通过 event.reply可以把数据传递到指定的通道中
ipcMain.on('tong_01', (event, arg) => {
const item = arg + 1
console.log(item)
event.reply('reply_01', item)
})
回到组件,如果是通过on监听,每当event.reply(‘reply_01’, item)主进程往reply_01传递数据,ipcRenderer.on就会触发并且拿到数据
window.electron.ipcRenderer.on('reply_01', (_event: unknown, res: number) => {
console.log(res)
setCount(res)
})
通过ipcRenderer.once监听,和on一样,但是once监听一次之后就会自动销毁
window.electron.ipcRenderer.once('reply_01', (_event: unknown, res: number) => {
console.log(res)
setCount(res)
})
如果采用的是ipcRenderer.on需要在组件销毁的时候关闭监听,这里是React,在useEffect的return中销毁
return (): void => {
window.electron.ipcRenderer.removeAllListeners('reply_01')
}
示例一: 通过ipcRenderer.invoke实现通信
在渲染进程中通过ipcRenderer.invoke指定通道发送数据,返回一个promise,通过await拿到promise的返回值 进行操作
const handlesubmit = async (): Promise<void> => {
const res = await window.electron.ipcRenderer.invoke('tong_01', count)
setCount(res)
}
在主进程中通过ipcMain.handle生产这个通道,ipcMain.handle和ipcRenderer.invoke结合async、await使用可以实现优雅的主进程和渲染进程之间的通信
ipcMain.handle('tong_01', (event, arg) => {
const item = arg + 1
console.log(item) // 打印处理结果
return item // 返回处理结果给渲染进程
})
什么时候使用 send + reply,什么时候使用 invoke + handle?
- 使用 send + reply 适合的场景:
- 不需要获取返回值:如果渲染进程只需要发送消息到主进程,不需要等待主进程返回数据,可以使用 send 和 reply。
- 事件驱动的场景:如果需要监听同一个通道的多个事件,或需要在主进程做一些长期的处理并通知多个渲染进程,send + reply 更加合适。
- 性能要求较低的简单任务:对于一些简单的任务,直接用 send + reply 的方式已经足够。
- 使用 invoke + handle 适合的场景:
- 需要获取返回值:当渲染进程需要等待主进程的计算结果(如数据库查询、文件读取等)时,invoke 更适合,因为它提供了一个 Promise 来等待异步操作的结果。
- 代码清晰简洁:invoke 和 handle 使得代码更加直观,尤其是与 async/await 一起使用时,能够减少回调函数的嵌套,增强可读性。
避免重复事件监听:如果不希望渲染进程重复注册事件监听器,invoke 也能帮助避免事件监听器的多次注册问题。
2 shell 方法
shell 模块允许渲染进程调用外部程序或操作文件。最新的electron已经不支持这种写法了,但是shell模块依然存在,通过ipcRenderer方法通知主线程之后,在主线程之中调用shell模块
方法 | 用途 |
---|---|
shell.openExternal(url) | 在默认浏览器中打开一个 URL |
shell.openPath(path) | 打开指定的文件或文件夹 |
shell.trashItem(path) | 将指定文件移到回收站 |
shell.showItemInFolder(fullPath) | 在文件管理器中显示文件 |
React 使用示例
下面是一个React组件,包含4个按钮
function Shell(): JSX.Element {
const handeleExternal = (): void => {
window.electron.ipcRenderer.send('open_external', 'https://www.baidu.com')
}
const handelePath = (): void => {
window.electron.ipcRenderer.send('open_path', 'C:/111')
}
const handeleDel = (): void => {
window.electron.ipcRenderer.send('del_path', 'C:\\111\\444.txt')
}
const handeleShow = (): void => {
window.electron.ipcRenderer.send('open_show', 'C:\\111\\333')
}
return (
<>
<h1>Shell</h1>
<div>
<button onClick={handeleExternal}> shell.openExternal </button>
<p> 在默认浏览器中打开一个 URL ('https://www.baidu.com')</p>
</div>
<div>
<button onClick={handelePath}> shell.openPath </button>
<p> 打开指定文件夹,后续通过其他方法获取当前文件夹打开,也可以编写一个输入框进行</p>
</div>
<div>
<button onClick={handeleDel}> shell.trashItem </button>
<p> 删除文件或者文件夹,删除文件要把后缀补全 </p>
</div>
<div>
<button onClick={handeleShow}> shell.showItemInFolder </button>
<p> 打开并且高亮文件或者文件夹,高亮文件需要把后缀补全</p>
</div>
</>
)
}
export default Shell
shell.openExterna
渲染线程
const handeleExternal = (): void => {
window.electron.ipcRenderer.send('open_external', 'https://www.baidu.com')
}
主线程
ipcMain.on('open_external', (_event, arg) => {
console.log(arg)
// event.reply('reply_01', item)
shell
.openExternal(arg)
.then(() => {
console.log('ok')
})
.catch((_err) => console.log('err'))
})
shell.openPath
渲染线程
const handelePath = (): void => {
window.electron.ipcRenderer.send('open_path', 'C:/111')
}
主线程
ipcMain.on('open_path', (_event, arg) => {
shell
.openPath(arg)
.then(() => {
console.log('ok')
})
.catch((_err) => console.log('err'))
})
shell.trashItem
渲染线程
const handeleDel = (): void => {
window.electron.ipcRenderer.send('del_path', 'C:\\111\\444.txt')
}
主线程
// 引入path模块 使用path.normalize确保路劲万无一失
const path = require('path')
ipcMain.on('del_path', (_event, arg) => {
const folderPath = path.normalize(arg)
console.log(folderPath)
// event.reply('reply_01', item)
shell
.trashItem(folderPath)
.then(() => {
console.log('ok')
})
.catch((_err) => console.log(_err))
})
shell.showItemInFolder
渲染线程
const handeleShow = (): void => {
window.electron.ipcRenderer.send('open_show', 'C:\\111\\333')
}
主线程
ipcMain.on('open_show', (_event, arg) => {
const folderPath = path.normalize(arg)
console.log(folderPath)
shell.showItemInFolder(folderPath)
})
3 clipboard 方法
clipboard 模块允许操作系统剪贴板。
方法 | 用途 |
---|---|
clipboard.writeText(text) | 将文本写入剪贴板 |
clipboard.readText() | 从剪贴板读取文本 |
clipboard.writeImage(image) | 将图片写入剪贴板 |
clipboard.readImage() | 从剪贴板读取图片 |
这个模板的’electron没有默认导出clipboard,需要直接去preload的index文件中添加
除此之外,ts会出现类型检查的错误,需要去接口的文件添加
React 使用示例
![function Clip(): JSX.Element {
const handelewriteText = (): void => {
console.log('向粘贴板存内容')
window.electron.clipboard.writeText('Hello, Clipboard!2')
}
const handeleRead = (): void => {
const txt = window.electron.clipboard.readText()
console.log('读取粘贴板的内容', txt)
}
return (
<>
<h1>Shell</h1>
<div>
<button onClick={handelewriteText}> clipboard.writeText </button>
<p> 往粘贴板里放文本 </p>
</div>
<div>
<button onClick={handeleRead}> clipboard.readText </button>
<p> 读取粘贴板的文本</p>
</div>
</>
)
}
export default Clip
4 dialog 方法
dialog 用于显示对话框。
方法 | 用途 |
---|---|
dialog.showOpenDialog(options) | 显示文件或文件夹选择对话框 |
dialog.showSaveDialog(options) | 显示保存文件对话框 |
dialog.showMessageBox(options) | 显示消息对话框 |
dialog.showErrorBox(title, content) | 显示错误对话框 |
React 使用示例
const openFile = async () => {
const result = await window.electron.dialog.showOpenDialog({
properties: ['openFile', 'multiSelections'],
});
console.log('Selected files:', result.filePaths);
};
5 自定义 electronAPI
开发者可以在 preload.js 中添加自定义方法并暴露给渲染进程。
preload.js 示例
const { contextBridge, ipcRenderer } = require('electron');
contextBridge.exposeInMainWorld('electron', {
ipcRenderer: {
send: (channel, ...args) => ipcRenderer.send(channel, ...args),
invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args),
on: (channel, listener) => ipcRenderer.on(channel, listener),
},
customApi: {
getAppVersion: () => ipcRenderer.invoke('get-app-version'),
},
});
React 使用自定义方法
const getAppVersion = async () => {
const version = await window.electron.customApi.getAppVersion();
console.log('App version:', version);
};