天天看點

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

Electron 已經不算新技術,最早是 github 從 Atom 編輯器衍生出來的架構。通過編寫 Javascript, HTML, CSS 能快速編譯出跨系統的桌面 app。Electron 的出現使得作為前端開發工程師的我們輸出範圍更廣。

分享最近用 Electron 做的一個基于番茄工作法的小應用,由于實作難度不大,市面上已經有非常多類似的app。我們嘗試用 Electron 來實作一個。

最終效果預覽:

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

? 工作法

番茄工作法的核心是将任務顆粒拆分到機關時間内(25分鐘)可以完成,在這25分鐘内專注在這個任務三,不允許做任何與任務無關的事,在任務任務完成之後可以短暫休息一會,再繼續工作。

是以這個 app 的重點是讓你建立任務,⏳ 25分鐘,幫讓 focus on 目前在做的任務。

站在巨人的肩膀上開發

嘗試新技術的時候,不要從零開始學習如何搭建技術棧,先做出來,遇到問題再查。 Electron 社群有很多優秀的沉澱,工具,模闆,元件,教程等等。

搜尋 react 關鍵字,找到了 electron-react-boilerplate 這個樣闆庫, 這個庫已經內建了 

react

redux

sass

flow

hmr

webpack

 等工具,同時準備好 

electron-builder

 打包工具,作為 

electron

 新手,我們優先選擇開箱即用的工具,快速開啟業務開發。

SVG 和 React Component

大概畫了一下草圖,準備進入開發階段。考慮後面會用到 svg icon,先在 FlatIcon 上找些免費的圖示,下載下傳 SVG 檔案。

通過 SVGR 線上工具導入 svg 内容生成 React Component 代碼。(svgr 也有 cli 等工具)

用 SVG Component 的好處是可以在代碼上更靈活地控制樣式,相比 png 圖示可互動性強,複用率高。

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

托盤和托盤彈窗

這個 app 啟動的時候就隐藏在托盤菜單的一角,點選的時候顯示 BrowserWindow,通過 Electron 提供的方法,可以獲得托盤和托盤彈窗的 Bounds 資訊,設定坐标位置。

const tray = new Tray(path.join(__dirname, '../static', 'tray.png'));

const mainWindow = new BrowserWindow({

frame: false,

resizable: true,

transparent: true

});

const showWindow = () => {

const { x, y } = getPositionFromActiveDisplay();

mainWindow.setPosition(x, y, true);

mainWindow.show();

};

const getPositionFromActiveDisplay = () => {

const trayBounds = tray.getBounds();

const windowBounds = mainWindow.getBounds();

const x = Math.round(trayBounds.x + trayBounds.width / 2 - windowBounds.width / 2);

const y = Math.round(trayBounds.y + trayBounds.height);

return { x, y };

};

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

?圖的三角是由前端代碼繪制的,加上 frame 和 electron 背景色,應該長這樣。

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

渲染線程和主線程

app 需要倒計時功能,告訴使用者距離任務完成時間還有多久。Electron 有渲染程序和主線程,BrowserWindow 不可見的時候,渲染程序會盡量減少消耗,是以如果 Tick 在渲染程序的話,當 app 處于背景時會出現非常大的時間偏差。這裡使用 Electron 提供的 ipcMain 和 ipcRenderer 做程序通信。

在主線程每秒發送 Tick 事件

// main.js

ipcMain.once('store-ready', event => {

const run = () => {

setTimeout(() => {

run();

event.sender.send('tick');

}, 1000);

};

run();

});

渲染程序就收事件并将 dispatch TICK action。

// app/index.js

const store = configureStore({

tasks: electronStore.getTasks()

});

ipcRenderer.send('store-ready');

ipcRenderer.on('tick', () => {

store.dispatch({

type: TICK

});

});

redux store 裡面判斷目前執行的任務計算倒計時時間。

switch (action.type) {

case TICK:

return {

...state,

rows: state.rows.map(task =>

task.id === state.currentId

? {

...task,

remain: Math.max(task.remain - 1, 0)

}

: task

)

};

資料持久存儲

資料持久化有很多種方案,因為是前端浏覽器,我們可以選擇 localStorage, Cookie,indexDB 等等。考慮可靠性,持久化以及存儲空間,還可以通過 Electron 寫檔案的方式,把資料寫入到應用路徑下。這樣即使 app 被解除安裝了,隻要資料沒被清空,使用者資料還在。

通過 Electron app getPath 可以獲得應用存儲路徑

import { app } from 'electron';

app.getPath('userData');

mac 下應用 app 的路徑是 

/Users/user/Library/ApplicationSupport/focus

。更簡單的方式可以直接用開源庫 

electron-store

,以 

key-value

 的格式存儲 json 檔案。

{

"tasks": {

"rows": [

{

"name": "任務名稱",

"id": "91ac7f05-76f4-46ea-addb-f392a3a29b54",

"created_at": 1553398427806,

"plan": 1500,

"remain": 0,

"done": true

}

],

"currentId": "91ac7f05-76f4-46ea-addb-f392a3a29b54"

}

}

倒計時 UI

有些樣式可能用 css 實作難度較大,而用 svg 的方式實作起來非常簡單。比如倒計時 UI,路徑圓角和路徑長度用 CSS 實作複雜度較高。可以在 Sketch 上直接繪制處理,導出成 svg,直接通過 react 代碼控制。

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

export default function(props: Props) {

const offset = percentage * totalLength;

const cx =

Math.cos(percentage * Math.PI * 2 - Math.PI * 0.5) * radius + radius;

const cy =

Math.sin(percentage * Math.PI * 2 - Math.PI * 0.5) * radius + radius;

return (

...others

<circle

id="path-1"

cx={cx}

cy={cy}

r="32"

fill="white"

style={{ transition: '1s linear' }}

/>

<path

...others

strokeLinecap="round"

strokeDasharray={totalLength}

strokeDashoffset={offset}

style={{ transition: '1s linear' }}

/>

svg>

);

}

臨界狀态判斷

app 在任務時間結束時需要有 Notification,由于?的 Tick 設計,判斷任務是否完成可以放在 redux middleware 上。

// middlewares/tasks

export default ({ getState }) => next => action => {

if (typeof action === 'object' && action.type === 'TICK') {

const beforeCount = getTimeEndTaksCount(getState);

next(action);

const afterCount = getTimeEndTaksCount(getState);

if (beforeCount !== afterCount) {

new Notification('Focus,任務完成了嗎?');

}

} else {

next(action);

}

};

經過一個 Tick action 之後,判斷任務完成數是否有變化,并使用 HTML5 Notification 通知使用者。

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

Travis CI

功能開發完畢之後,使用 

electron-builder

 進行打包釋出,建構之後推到 github release 下,使用者可以直接在這下載下傳到最新的包。

同樣的, 

boilerplate

 已經準備好 

.travis.yml

 檔案,唯一需要我們操作的是在 https://github.com/settings/tokens/new 上生成 token,在 https://www.travis-ci.org/ 建構之前配置 

Environment Variables

, 

GH_TOKEN

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

tirgger build, 成功之後就能看到建構成功過的包,下載下傳使用

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具

總結

使用 Electron,前端開發者可以使用自己的武器建構跨系統的桌面端應用,而且不用學習其他技術,缺點是一個小小的功能打包完的體積是 70M。

這個 app 從有想法到最終實作比預期的簡單,感興趣的同學也可以自己 DIY 些小玩意兒。完整的代碼在 github 上https://github.com/HelKyle/focus,歡迎體驗,同時也歡迎 star~

作者:HelKyle

https://juejin.im/post/5c966596e51d454d42032ce9

electron 托盤圖示閃爍_從零到一,用 Electron 開發桌面效率工具