单实例的思路
- 首次通过双击文件打开应用
- 将
filePath
传给render
- 将
- 使用中的应用,再次双击打开文件
- 第一个实例创建时,同时创建一个通信服务器
net.createServer()
- 第二个实例创建时,连接第一个服务器
net.createConnection()
- 将再次打开的
filePath
传递给第一个实例 - 然后在传递给render
- 第一个实例创建时,同时创建一个通信服务器
1. 首次通过双击文件打开应用
在主进程展示的时候传递filePath
ts
mainWindow.on('ready-to-show', () => {
//隐藏启动页
if (loadingWindow && !loadingWindow?.isDestroyed()) {
loadingWindow?.hide()
loadingWindow?.removeAllListeners()
loadingWindow?.destroy()
}
mainWindow.show()
/**
* @description 双击打开本地文件
*/
openFileFromDoubleClick(mainWindow)
})
获取filePath
并传递给render
ts
export function openFileFromDoubleClick(mainWindow) {
if (process.argv.length >= 2) {
const argv = process.argv.slice(app.isPackaged ? 1 : 2)
const filePath =
argv.find((arg) => arg.endsWith('.krzj')) ||
argv.find((arg) => arg.includes('--file'))?.split('=')[1]
if (filePath && filePath.endsWith('.krzj')) {
// 当页面加载完成后,获取到vue-ready事件后,发送open-file事件
ipcMain.once('vue-ready', () => {
mainWindow.webContents.send('open-file', filePath)
})
}
}
}
2. 注册preload
事件
ts
//双击打开文件
onOpenFile: (callback: any) => ipcRenderer.on('open-file', callback),
//消息传递
send: (channel, data) => ipcRenderer.send(channel, data),
3. render接收信息
需要先通知主进程render加载完毕,才从主进程拿filePath
,否则获取不到
ts
onMounted(() => {
// 在health接口返回后 获取双击打开的文件路径
window.api.send('vue-ready')
window.api.onOpenFile((event: any, path: string) => {
if (path && route.path === '/file') {
// 在当前页直接获取跳转
openProjectFile(path)
} else if (path && route.path !== '/file') {
// 在非当前页则回来后获取跳转
router.push('/file')
openProjectFile(path)
}
})
})
4. 主进程创建通信服务器
ts
// 锁定应用只能单列运行
const appSingleInstance = app.requestSingleInstanceLock()
if (!appSingleInstance) {
// 第二个实例 - 连接第一个实例的服务器
sendFilePathToFisrtInstance(PORT)
app.quit()
} else {
// 第一个实例 - 创建服务器 获取第二个实例发送的filepath 封装后不能再发送
server = net.createServer((socket) => {
socket.on('data', (data) => {
mainWindow?.webContents.send('open-file', data.toString())
})
})
server.listen(PORT)
server.on('error', (err) => console.error('服务器错误:', err))
}
5. 第二个实例连接服务器
ts
/**
* @description 第二个实例 - 连接第一个实例的服务器
* @export
*/
export function sendFilePathToFisrtInstance(port: number) {
const argv = process.argv.slice(app.isPackaged ? 1 : 2)
const filePath =
argv.find((arg) => arg.endsWith('.krzj')) ||
argv.find((arg) => arg.includes('--file'))?.split('=')[1]
if (filePath) {
const client = net.createConnection({ port: port }, () => {
client.write(filePath)
client.end()
})
client.on('error', () => {})
}
}
开发时如何本地测试打开多个文件
使用的是electron-vite
,在package.json
创建运行脚本,一条就是打开一个文件,可以开多个终端打开多个文件
ts
"open-file": "electron-vite dev -- --file \"D:/kr/untitled01.krzj\"",
"open-file1": "electron-vite dev -- --file \"D:/kr/untitled02.krzj\"",
"open-file2": "electron-vite dev -- --file \"D:/kr/untitled03.krzj\""
windows如何关联自定义文件关联启动
我是用的是electron-builder
,然后在electron-builder.yml中
配置就行,非常简单
yml
# 设置自定义文件关联启动
fileAssociations:
description: kingrayFile
# 自定义文件后缀
ext: krzj
# 自定义文件图标
icon: build/icons/win/icon.ico