前段時間,我用electron-vue開發了一款跨平臺(目前支持Mac和Windows)的免費開源的圖牀上傳應用——PicGo,在開發過程當中踩了很多的坑,不只來自應用的業務邏輯自己,也來自electron自己。在開發這個應用過程當中,我學了很多的東西。由於我也是從0開始學習electron,因此不少經歷應該也能給初學、想學electron開發的同窗們一些啓發和指示。故而寫一份Electron的開發實戰經歷,用最貼近實際工程項目開發的角度來闡述。但願能幫助到你們。html
預計將會從幾篇系列文章或方面來展開:前端
PicGo
是採用electron-vue
開發的,因此若是你會vue
,那麼跟着一塊兒來學習將會比較快。若是你的技術棧是其餘的諸如react
、angular
,那麼純按照本教程雖然在render端(能夠理解爲頁面)的構建可能學習到的東西很少,不過在main端(electron的主進程)應該仍是能學習到相應的知識的。vue
若是以前的文章沒閱讀的朋友能夠先從以前的文章跟着看。react
雖然electron在大多數狀況下的跨平臺措施已經幫咱們作得很好了。不過須要注意的是,不一樣平臺必然存在細節上的差別。咱們在書寫跨平臺應用的時候,若是隻在本身書寫平臺下測試經過的話是不足以說明咱們的應用是健壯的。(固然若是你只想提供給某個平臺那另當別論)因此針對不一樣的發佈平臺,就須要作一些兼容性措施。linux
就我本身的感覺而言,macOS平臺支持的特性相對比較多,而這裏面又不少是獨有的,因此不少能在macOS上實現的功能卻不必定能在windows上實現。因此對於windows用戶而言,在保證總體應用的可用性的狀況下,就有可能要相應地作一些妥協和犧牲。不過在windows上的一些操做習慣也能夠反過來服務於macOS平臺。這點我會在下面給出一個例子詳細說明。git
在開發electron應用的時候,不少時候咱們只注意去查找api名,卻容易忽視這個api可以使用的平臺。在官方文檔裏,對於一些獨佔的api,大多都會有標識標出:github
不過須要注意的是一些未有平臺標識的api裏的配置項,也有多是某個平臺的獨佔:web
平時開發的過程當中,用到文檔的地方仍是須要細細留心,避免後續沒必要要的麻煩。windows
上面講了這麼多,該到實例的時候了。在electron應用中,一般來講renderer
進程的東西不須要作太多的跨平臺措施——畢竟不論是哪一個平臺,都是跑在Chrome裏的頁面。因此大多數狀況下,這個方面的工做會放在main
進程裏。不過也有例外:api
下面是PicGo的windows版:
下面是PicGo的macOS版:
能夠發現除了顏色有些區別以外,頂部的title-bar
操做欄也有些區別。macOS的程序窗口習慣將窗口的縮放、關閉按鈕放在窗口的左上角。而windows程序則相反,它們喜歡放在窗口的右上角。因此爲了迎合用戶的操做習慣,咱們在開發electron程序的時候也應該注意到這一點。
固然,若是是經過普通的BrowserWindow
建立的窗口,那麼將會自動擁有常見的macOS、windows的頂部欄,以及默認的樣式。
我在這裏想說的是若是想要更加美觀的界面,一般咱們喜歡「沉浸式」的頂部欄。對於macOS而言,沉浸式的頂部欄就是將頂部欄的三個操做按鈕直接「嵌入」窗口主題的左上角。而對於windows而言,只能刪去頂部的三個操做按鈕,本身用前端的方式來實現了。因此這個地方兩個平臺的差別性就出來了。
在main
進程裏建立該窗口的時候,主要代碼以下:
const createSettingWindow = () => {
const options = {
height: 450,
width: 800,
show: false, // 當window建立的時候不用打開
center: true,
fullscreenable: false,
resizable: false,
title: 'PicGo',
vibrancy: 'ultra-dark', // 窗口模糊的樣式
transparent: true,
titleBarStyle: 'hidden', // title-bar的樣式——隱藏頂部欄的橫條,把操做按鈕嵌入窗口
webPreferences: {
backgroundThrottling: false
}
}
if (process.platform === 'win32') { // 若是平臺是win32,也即windows
options.show = true // 當window建立的時候打開
options.frame = false // 建立一個frameless窗口,詳情:https://electronjs.org/docs/api/frameless-window
options.backgroundColor = '#3f3c37'
}
settingWindow = new BrowserWindow(options)
settingWindow.loadURL(settingWinURL)
settingWindow.on('closed', () => {
settingWindow = null
})
}
複製代碼
主要的工具是經過process.platform
來判斷不一樣的平臺。當前可能的值有:
在這裏咱們基本上只須要關心darwin
(macOS)、win32
(windows)、linux
(Linux)這三個平臺便可。注意,因爲electron的對於renderer
進程的加持,在renderer
進程裏也能直接使用process.platform
來判斷當前的操做系統。這是一個很方便的特性。
針對windows平臺,因爲採用了frameless-window,因此咱們須要手動「繪製」頂部的縮放和關閉按鈕,並配上相應的事件來模擬真實的按鈕。
<div class="fake-title-bar">
PicGo - {{ version }}
<div class="handle-bar" v-if="process.platform === 'win32'"><!-- 若是是windows平臺 -->
<i class="el-icon-minus" @click="minimizeWindow"></i>
<i class="el-icon-close" @click="closeWindow"></i>
</div>
</div>
複製代碼
相應的事件以下:
minimizeWindow () {
const window = BrowserWindow.getFocusedWindow()
window.minimize()
},
closeWindow () {
const window = BrowserWindow.getFocusedWindow()
window.close()
},
複製代碼
簡單來講就是調用了BrowserWindow
的方法來獲取當前激活的窗口,而後再對這個窗口進行縮小或關閉的操做。其實也不難對吧!
針對不一樣的平臺,我對PicGo的任務欄圖標交互也有所區別。對於macOS而言,點擊頂部菜單欄的時候會彈出一個小窗口:
因爲macOS的頂部欄圖標能夠接受拖拽事件,因此就針對macOS的頂部欄製做了頂部欄圖標對應的小窗口。讓大部分操做不通過主窗口也能實現。而對於windows而言,沒有頂部欄,取而代之的是位於底部欄的右側的任務欄,一般點擊任務欄裏的圖標就會把應用的主窗口調出來。因此爲了迎合不一樣平臺的操做習慣,我對於這個地方也作了相應的兼容性適配:
tray.on('click', () => { // 不論是頂部欄的圖標仍是任務欄的圖標都是Tray組件生成的
if (process.platform === 'darwin') { // 若是是macOS平臺
let img = clipboard.readImage()
let obj = []
if (!img.isEmpty()) {
// 從剪貼板來的圖片默認轉爲png
const imgUrl = 'data:image/png;base64,' + Buffer.from(img.toPNG(), 'binary').toString('base64')
obj.push({
width: img.getSize().width,
height: img.getSize().height,
imgUrl
})
}
toggleWindow() // 打開小窗口
setTimeout(() => {
window.webContents.send('clipboardFiles', obj)
}, 0)
} else {
window.hide()
if (settingWindow === null) { // 若是主窗口未建立
createSettingWindow() // 建立
settingWindow.show() // 並打開
} else {
settingWindow.show() // 若是已存在,打開
settingWindow.focus() // 並激活
}
}
})
複製代碼
在windows平臺上,一般咱們把應用的窗口都關了以後也就默認把這個應用給退出了。而若是在macOS系統上卻不是這樣。咱們把應用的窗口關閉了,可是並不是徹底退出這個應用。因此爲了實現這個操做習慣,咱們也能夠增長一個狀況判斷:
app.on('window-all-closed', () => { // 當窗口都被關閉了
if (process.platform !== 'darwin') { // 若是不是macOS
app.quit() // 應用退出
}
})
複製代碼
本文簡要地講述了electron應用在跨平臺開發的時候的一些注意事項。可能不少人會以爲奇怪我爲啥把這個章節單獨拎出來說。不少時候咱們只關注於應用的開發過程,把應用的功能實現是不少狀況下的「終極」目標。然而真實狀況是,應用的功能實現只是「基本」目標。一個應用要給用戶使用的話必然不只要考慮到應用的功能,還必須考慮用戶的使用習慣。要站在用戶的角度來作應用。而不是作自嗨型的應用。因此這篇文章也但願可以幫助想要開發electron應用的你。
本文不少都是我在開發PicGo
的時候碰到的問題、踩的坑。也許文中簡單的幾句話背後就是我無數次的查閱和調試。但願這篇文章可以給你的electron-vue
開發帶來一些啓發。文中相關的代碼,你均可以在PicGo的項目倉庫裏找到,歡迎star~若是本文可以給你帶來幫助,那麼將是我最開心的地方。若是喜歡,歡迎關注個人博客以及本系列文章的後續進展。
注:文中的圖片除未特意說明以外均屬於我我的做品,須要轉載請私信