原文地址: electron開發採坑小記-SegmentFault 思否
前前前前段時間作了個桌面端的項目(這篇文章拖了挺久了),功能大概是這樣的:javascript
feed
流信息展現webview
打開一個網站需求很簡單,提升運營效率的輔助工具,可是由於一些緣由須要作成一個桌面端。
從前端一會兒跨到PC桌面端開發,聽起來跨度有點大,但在實際的開發中由於有了electron
的加持,這一切都變的很是便利,絲毫沒有跨度的痕跡,徹底變成了web開發那一套,讓人不由感嘆js生態的完善,就像有句話說的:html
能用JavaScript書寫的終將會用JavaScript書寫。
實際上我並不是直接採用electron
,而是使用了更加懶人的electron-vue。經過這一工具將web
開發那一套又轉移到vue
開發上,再輔以iview
作UI,開發起來一會兒高效了很多。前端
咱們知道electron
,可是electron-vue
是個什麼東西呢,咱們還須要瞭解一下。這東西的官方介紹是這樣的。vue
An Electron & Vue.js quick start boilerplate with vue-cli scaffolding, common Vue plugins, electron-packager/electron-builder, unit/e2e testing, vue-devtools, and webpack.
從這個介紹大體能夠看出來這是個基於vue-cli
的使用vue
開發electron
應用的腳手架。能夠幫助咱們作很多的vue
與electron
之間結合的基礎工做,讓咱們的開發更加便捷。那麼咱們就來看看使用electron-vue
怎麼作開發。咱們先從基礎的安裝開始。java
我以爲這個步驟叫安裝並非很嚴謹,由於electron-vue
並非一個單獨的npm
包,而是vue-cli
的一個模板配置。因此使用起來沒有難度,能夠按照官方文檔的說明便可完成,只有兩行命令。webpack
# 安裝 vue-cli 和 腳手架樣板代碼 npm install -g vue-cli vue init simulatedgreg/electron-vue my-project
如此,咱們便獲得了一個初始化的electron
項目,安裝完依賴包就能開發了。初始化過程很簡單,可是須要提示一些vue cli
使用過程當中須要注意的問題:git
Vue CLI
的包名稱由vue-cli
改爲了@vue/cli
,致使最新版的vue cli
使用vue init
命令會報錯,而electron-vue
的安裝文檔比較老舊,須要用vue init
這個命令,咱們能夠用一個命令來作橋接:github
npm install -g @vue/cli-init
windows
在Git bash
上初始化選擇插件時候沒法用上下鍵交互的問題能夠換用powershell
項目初始化、安裝依賴後咱們就能夠開發了。這時候能夠跑一下項目,他會有個默認的界面。web
npm run dev
對應的目錄是這樣的(目錄會根據安裝插件的不一樣而存在差別)。ajax
├── appveyor.yml ├── build │ └── icons │ ├── 256x256.png │ ├── icon.icns │ └── icon.ico ├── dist │ ├── electron │ └── web ├── package.json ├── README.md ├── src │ ├── index.ejs │ ├── main │ │ ├── index.dev.js │ │ └── index.js │ └── renderer │ ├── App.vue │ ├── assets │ ├── components │ ├── main.js │ ├── router │ └── store └── static
大體的套路跟vue
開發同樣,不一樣的是src
下有個兩個目錄:main
和renderer
。咱們大體能夠理解爲:
main
目錄存放與electron
相關的內容,是主進程renderer
目錄存放與咱們頁面相關的內容,是渲染進程這個經過這個demo頁面能夠驗證。搞清楚這個後開發就很簡單了,不須要解釋太多。更多的介紹能夠看文檔
開發過程當中調試是不可避免的,根據個人經驗這裏主要介紹兩種調試:
這種調試就像咱們平時在vue
開發web
應用中使用devtool
同樣。這個在初始化的代碼中已經寫好了,在dev
模式下默認是開啓的。
在/src/main/index.dev.js
能夠找到這段代碼,咱們不用太關心。
require('electron-debug')({ showDevTools: true })
webview
頁面調試這個是由於我這個項目須要才涉及到的,須要本身代碼實現。 在個人邏輯中大體這樣處理的:
<webview ref="webview" src="xxx" ></webview>
this.$refs.webview.addEventListener('dom-ready', res => { if (process.env.NODE_ENV === 'development') { this.$refs.webview.openDevTools(); } });
開發完以後咱們須要把代碼打包成一個exe
的可執行文件,這個操做也很簡單,已經在package.json
上被安排好了,咱們直接用就好了。
npm run build
而後,build
目錄下有會有你想要的exe
文件了。拷走安裝就能夠用了。
若是你須要自定義一些圖標啥的能夠改package.json
中build
的相關配置,操做簡單,不用多提。
由於此次項目功能很簡單,涉及到的點不多,因此這裏只介紹項目用到的一些核心點,沒用過的沒有發言權,就不提了。
webview
代碼注入electron
提供了webview
標籤可以讓咱們嵌入本身的網頁。想要往裏面注入代碼可使用webview
上提供的executeJavaScript
方法。具體的參數和使用方法這些都是文檔層面的內容,不用多提,須要注意的是這個方法的第三個參數是個callback
,文檔上是這樣描述的
callback Function (可選) - 在腳本被執行後被調用。
文檔只是描述了這個回調被觸發的時機,而沒有描述回調觸發時候傳的參數。
關於觸發時機和參數,更具體的描述是這樣的。
querySelector
這樣的,callback
會在注入代碼執行完以後觸發,而且把你最後querySelector
得到的值傳入callback
ajax
請求這樣的,callback
是不會等這個請求有了響應才執行的,而是執行完ajax
請求就執行,固然,這種狀況下callback
是沒有傳參的。咱們後面會介紹怎麼拿到注入ajax
的返回值。主進程和渲染進程通訊是electron
中很重要的概念,介紹這塊內容的文章也有不少,因此這裏就不過多贅述,簡單介紹一下大概狀況。
通訊主要靠兩個工具完成:ipcRenderer
和ipcMain
。
在主進程裏這樣使用ipcMain
:
const { ipcMain } = require('electron'); ipcMain.on('exit_app', res => { app.exit(); })
在渲染進程中這樣使用ipcRenderer
:
const { ipcRenderer } = require('electron'); ipcRenderer.send('exit_app', true);
須要注意的是:消息只能是由渲染進程主動發起,主進程被動監聽,而後主進程做響應,不存在由主進程主動向渲染進程通訊的方式。代碼實現以下:
// 在主進程中 const { ipcMain } = require('electron') ipcMain.on('asynchronous-message', (event, arg) => { console.log(arg) // prints "ping" event.reply('asynchronous-reply', 'pong') }) ipcMain.on('synchronous-message', (event, arg) => { console.log(arg) // prints "ping" event.returnValue = 'pong' })
//在渲染器進程 (網頁) 中 const { ipcRenderer } = require('electron') console.log(ipcRenderer.sendSync('synchronous-message', 'ping')) // prints "pong" ipcRenderer.on('asynchronous-reply', (event, arg) => { console.log(arg) // prints "pong" }) ipcRenderer.send('asynchronous-message', 'ping')
electron
窗體關閉事件攔截窗體關閉事件攔截利用的是BrowserWindow
的close事件來作處理的。須要注意的是BrowserWindow
實例還有個closed
事件,區別在於:
close
在窗口要關閉的時候觸發closed
窗口已經關閉時觸發這個兩個事件一個字母的差距,可是觸發時機卻大有差距,千萬分清楚,當時我就是沒看清,浪費了很多時間。
窗體關閉事件攔截的代碼實現大體以下:
mainWindow = new BrowserWindow({ height: 563, useContentSize: true, width: 1000 }) mainWindow.on('close', event => { return event.preventDefault(); })
webview
中beforeunload
彈窗問題若是內嵌的webview
中對beforeunload
事件有監聽,並有彈窗操做,那麼這個事件觸發的時候,electron
是沒有彈窗提示的。用戶是沒有感知的,這個問題尚未解決辦法,是個坑。
(electron
的webview
是不會顯示這些彈窗)
webview
中注入請求的響應個人項目裏有一個需求是要向webview
中注入ajax
請求,而且要拿到請求的響應結果。可是electron
中比較早的版本中只有對發起的請求有監聽,並不支持監聽請求的響應,因此要拿到請求的響應結果就是個問題。
可是也不是沒辦法解決。我這裏是藉助webview
的console-message
事件來處理。監聽webview
的console-message
事件,當拿到請求的響應的時候把響應的內容按照約定的格式打出來,這樣就間接的實現了對注入請求的監聽。
electron
低版本webview
中不能跳轉這是一個在electron
低版本中存在的問題,在一些新的版本中已經解決了。
這個問題的具體表現就是:
內嵌webview
的頁面中若是發生302
、301
跳轉的話頁面會卡在發生跳轉的請求那裏再也不向下進行,查看webview
的network
能夠看到這個問題。
這個問題的解決很簡單,升級到最新的electron
就能解決這個問題。我這裏升級到4.1.4
解決了這個問題。
由於electron-vue
長時間沒更新,裏面使用的electron
版本仍是2.0.4
,比較老舊,因此你要是遇到一些奇奇怪怪的問題不妨升級electron
來嘗試解決。
ctrl+c
以後仍有electron
進程駐守調試時候發現的這個問題,雖然是在electron
中開發,可是由於仍是vue
那一套,因此咱們改完代碼就不用重啓就能在electron
中看到效果,就是熱更新嘛,可是有時候我仍是會手動的ctrl + c
,這麼手動的次數多了以後我發現個人電腦會變的很是卡。排查後我發現ctrl + c
並不能徹底關閉整個electron
應用,每次這麼作都會遺留2個electron
進程保持活躍,屢次以後會遺留不少electron
進程,電腦就會變的很是卡,每次都須要手動殺一下進程。這個問題在把模板中自帶的
app.on('window-all-closed', event => { app.quit(); });
替換爲
app.on('window-all-closed', event => { app.exit(); });
以後解決(在寫文章的時候發現這個問題並沒獲得復現,不知道是否是新的版本修復了這個問題),其中差別感興趣的能夠深刻研究一下。
解決上面問題的時候發現electron
沒法捕獲來自命令行的信號量。若是有這個需求的話仍是要留意的。
在開發過程當中也是一邊學一邊作,發現了一些不錯的文章和博客,從裏面也得到了很多的幫助,貼出來分享一下。