單實例的思路
- 首次通過雙擊文件打開應用
- 將
filePath
傳給render
- 將
- 使用中的應用,再次雙擊打開文件
- 第一個實例創建時,同時創建一個通信服務器
net.createServer()
- 第二個實例創建時,連接第一個服務器
net.createConnection()
- 將再次打開的
filePath
傳遞給第一個實例 - 然后在傳遞給render
- 第一個實例創建時,同時創建一個通信服務器
1. 首次通過雙擊文件打開應用
在主進程展示的時候傳遞filePath
mainWindow.on('ready-to-show', () => {//隱藏啟動頁if (loadingWindow && !loadingWindow?.isDestroyed()) {loadingWindow?.hide()loadingWindow?.removeAllListeners()loadingWindow?.destroy()}mainWindow.show()/*** @description 雙擊打開本地文件*/openFileFromDoubleClick(mainWindow)})
獲取filePath
并傳遞給render
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
事件
//雙擊打開文件onOpenFile: (callback: any) => ipcRenderer.on('open-file', callback),//消息傳遞send: (channel, data) => ipcRenderer.send(channel, data),
3. render接收信息
需要先通知主進程render加載完畢,才從主進程拿filePath
,否則獲取不到
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. 主進程創建通信服務器
// 鎖定應用只能單列運行
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. 第二個實例連接服務器
/*** @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
創建運行腳本,一條就是打開一個文件,可以開多個終端打開多個文件
"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中
配置就行,非常簡單
# 設置自定義文件關聯啟動
fileAssociations:description: kingrayFile# 自定義文件后綴ext: krzj# 自定義文件圖標icon: build/icons/win/icon.ico