上一篇講了使用electron進行打包的配置相關文件,這篇主要講electron中很重要的通信方式.
首先解釋一個概念: electron打包的應用包含兩個部分
- electron的環境(node),也就是主進程.
- web渲染環境,副進程.
這兩個環境之間是相互隔離的,無法直接進行數據通信,所以有了這篇文章.
三個角色:
- ipcRender
- ipcMain
- webContents
ipcRenderer用於渲染進程
- ipcRenderer.on(channel, listener) --> channel為事件頻道,字符串.listener為觸發回調函數,用於響應webContent.send()
- ipcRenderer.send(channel, data) --> 概念同上,用於向ipcMain發送異步信息.
- ipcRenderer.sendSync(channel, data) --> 用於向ipcMain發送同步信息,此時會阻塞掉渲染進程,除非必須,謹慎使用.
ipcMain用於主進程,響應從渲染進程中發送的消息
- ipcMain.on(channel,listener) --> 響應從ipcRender中相同channel.
- ipcMain.once(channel,listener) --> 同上,但是只觸發一次,觸發后自動取消綁定
- ipcMain.removeListener(channel,listener) --> 移除時事件,listener一定要為函數引用,不能是匿名函數或箭頭函數,否則不能解綁
- ipcMain.removeAllListener([channel]) --> 移除channel上的所有事件 listener (event, data)
- event.sender.send(channel, data) --> 這是唯一ipcMain可以異步返回消息的方法,通過event參數向渲染進程發送消息.(與ipcRenderer.send對應)
- event.returnValue(channel,data) --> ipcMain同步返回消息(與ipcRenderer.sendSync對應)
- data是消息發送者攜帶的data
最后一個是webContent
不知道細心的讀者有沒有發現,ipcMain本身是無法直接發送事件的,只能通過響應事件回調的event來發送,那如果我們想先讓主進程發送消息呢?那就才用這個辦法.這個webcontent是在BrowserWIndow實例中的方法
- webContent.send(channel,data) --> 主進程向渲染進程發送消息.
注意,這些方法全部需要在主進程已經創建了BrowserWindow之后才有效,下面來一個例子:
在關閉客戶端之前需要判斷已修改的文件已保存.下圖為流程圖:
首先是渲染端代碼:
const electron = require('electron') // 引入electron const ipcRenderer = electron.ipcRenderer; // 獲取ipcRender渲染進程 let to_close = false // 定義允許關閉變量 ipcRenderer.on('save_complete', () => to_close = true) // 如果保存完成則設置為可以關閉 ipcRenderer.on('not_save', () => to_close = false) // 否則設置為不可關閉 // 全局的點擊關閉按鈕后調用 window.onbeforeunload = (e) => { !to_close && (e.returnValue = false) // 如果不允許關閉則return false阻止關閉 ipcRenderer.send('need_close') // 發送需要進行關閉信息 }
其次是主進程代碼
const electron = require('electron') const app = electron.app const dialog = electron.dialog // 創建對話框 const BrowserWindow = electron.BrowserWindow const ipcMain = electron.ipcMain let need_close = false // 是否需要關閉(如果只是點擊保存則不需要關閉) ipcMain.on('need_close', () => need_close = true) // 如果需要,則設為true // 當點擊保存時 mainWindow.webContents.session.on('will-download', (event, downloadItem,webContents) => { // 阻止默認保存行為(點擊a標簽) event.returnValue = false; // 顯示保存對話框,默認擴展為.txt const fileName = dialog.showSaveDialog({ defaultPath: '新的作品', filters: [ { name: 'txt', extensions: ['txt'] }], }); // 如果沒有正常保存 if (typeof fileName == 'undefined') { // 不能退出 need_close = false // 向渲染端發送沒有保存消息 webContents.send('not_save') // 取消下載 return downloadItem.cancel(); } // 正常下載 downloadItem.setSavePath(fileName); // 當下載項結束時 downloadItem.on('done', (event, state) => { // 有三種state completed, cancelled, interrupted,此處只監聽完成時 if (state === 'completed') { // 發送完成保存 webContents.send('save_complete') // 如果需要關閉的話則退出app need_close && app.quit(); } }); })
這是很簡單的展示了如何在渲染端以及服務端進行消息傳遞.可以基本滿足通信需求.