Electron 實戰桌面計算器應用

原文地址:http://blog.gdfengshuo.com/article/22/html

前言

Electron 是一個搭建跨平臺桌面應用的框架,僅僅使用 JavaScript、HTML 以及 CSS,便可快速而容易地搭建一個原生應用。這對於想要涉及其餘領域的開發者來講是一個很是大的福利。
node

原文做者:林鑫,做者博客:http://blog.gdfengshuo.com/git

項目介紹

倉庫地址:lin-xin/calculatorgithub

我這裏經過 Electron 實現了仿 iPhone 的計算器,經過菜單能夠切換橫屏和豎屏,橫屏有更多的運算。而對於 JavaScript 進行浮點數計算來講,精度丟失是個很大問題,因此我這裏使用了第三方庫 math.js 來解決這個精度的問題。
儘量的實現了跟 iPhone 同樣的運算:web

  • 1 + 2 × 3 = 7
  • 3 += 6 (再按 = 等於 9)
  • 0.1 + 0.2 = 0.3 (浮點數精度處理)

Image text
Image text

不過我下面並非要講計算器,而是用到的 Electron 的知識點。shell

生命週期

在主進程中經過 app 模塊控制整個應用的生命週期。npm

當 Electron 完成初始化時觸發 ready 事件:windows

app.on('ready', () => {
    // 建立窗口、加載頁面等操做
})

當全部的窗口都被關閉時會觸發 window-all-closed 事件:api

app.on('window-all-closed', () => {
    if(process.platform !== 'darwin'){
        app.quit();     // 退出應用
    }
})

在開發中發現,沒有監聽該事件,打包後的應用關閉後,進程還保留着,會佔用系統的內存。數組

窗口

原本咱們的 html 只顯示在瀏覽器中,而 electron 提供了一個 BrowserWindow 模塊用於建立和控制瀏覽器窗口,咱們的頁面就是顯示在這樣的窗口中。

建立窗口

經過關鍵字 new 實例化返回 win 對象,該對象有豐富的方法對窗口進行控制。

win = new BrowserWindow({
    width: 390,         // 窗口寬度
    height: 670,        // 窗口高度
    fullscreen: false,  // 不容許全屏
    resizable: false    // 不容許改變窗口size,否則佈局就亂了啊
});

加載頁面

窗口建立完是一片空白的,能夠經過 win.loadURL() 來加載要顯示的頁面。

const path = require('path');
const url = require('url');

win.loadURL(url.format({    // 加載本地的文件
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file',
    slashes: true
}))

也能夠直接加載遠程連接 win.loadURL('http://blog.gdfengshuo.com');

菜單

桌面應用菜單欄是最多見的功能。Electron 提供了 Menu 模塊來建立原生的應用菜單和 context 菜單,

const template = [                              // 建立菜單模板
    {
        label: '查看',
        submenu: [
            {label: '豎屏', type: 'radio', checked: true},      // type 屬性讓菜單爲 radio 可選
            {label: '橫屏', type: 'radio', checked: false},
            {label: '重載',role:'reload'},
            {label: '退出',role:'quit'},
        ]
    }
]

const menu = Menu.buildFromTemplate(template);  // 經過模板返回菜單的數組
Menu.setApplicationMenu(menu);                  // 將該數組設置爲菜單

在子菜單中,經過點擊豎屏或橫屏來進行一些操做,那就能夠給 submenu 監聽 click 事件。

const template = [
    {
        label: '查看',
        submenu: [
            {
                label: '橫屏'
                click: () => {              // 監聽橫屏的點擊事件
                    win.setSize(670,460);   // 設置窗口的寬高
                }
            }
        ]
    }
]

主進程和渲染進程通訊

雖然點擊橫屏的時候,能夠設置窗口的寬高,可是要如何去觸發頁面裏的方法,這裏就須要主進程跟渲染進程之間進行通訊。

主進程,能夠理解爲 main.js 用來寫 electron api 的就是主進程,渲染進程就是渲染出來的頁面。

ipcMain

在主進程中可使用 ipcMain 模塊,它控制着由渲染進程(web page)發送過來的異步或同步消息。

const {ipcMain} = require('electron')
ipcMain.on('send-message', (event, arg) => {
    event.sender.send('reply-message', 'hello world')
})

ipcMain 監聽 send-message 事件,當消息到達時能夠調用 event.sender.send 來回復異步消息,向渲染進程發送 reply-message 事件,也能夠帶着參數發送過去。

ipcRenderer

在渲染進程能夠調用 ipcRenderer 模塊向主進程發送同步或異步消息,也能夠收到主進程的相應。

const {ipcRenderer} = require('electron')
ipcRenderer.on('reply-message', (event, arg) => {
    console.log(arg);       // hello world
})

ipcRenderer.send('anything', 'hello everyone');

ipcRenderer 能夠監聽到來自主進程的 reply-message 事件並拿到參數進行操做,也可使用 send() 方法向主進程發送消息。

webContents

webContents 是一個事件發出者,它負責渲染並控制網頁,也是 BrowserWindow 對象的屬性。在 ipcMain 中的 event.sender,返回發送消息的 webContents 對象,因此包含着 send() 方法用於發送消息。

const win = BrowserWindow.fromId(1);        // fromId() 方法找到ID爲1的窗口
win.webContents.on('todo', () => {
    win.webContents.send('done', 'well done!')
})

remote

remote 模塊提供了一種在渲染進程(網頁)和主進程之間進行進程間通信(IPC)的簡便途徑。在 Electron 中,有許多模塊只存在主進程中,想要調用這些模塊的方法須要經過 ipc 模塊向主進程發送消息,讓主進程調用這些方法。而使用 remote 模塊,則能夠在渲染進程中調用這些只存在於主進程對象的方法了。

const {remote} = require('electron')
const BrowserWindow = remote.BrowserWindow      // 訪問主進程中的BrowserWindow模塊

let win = new BrowserWindow();                  // 其餘的跟主進程的操做都同樣

remote 模塊除了能夠訪問主進程的內置模塊,自身還有一些方法。

remote.require(module)          // 返回在主進程中執行 require(module) 所返回的對象
remote.getCurrentWindow()       // 返回該網頁所屬的 BrowserWindow 對象
remote.getCurrentWebContents()  // 返回該網頁的 WebContents 對象
remote.getGlobal(name)          // 返回在主進程中名爲 name 的全局變量(即 global[name])
remote.process                  // 返回主進程中的 process 對象,等同於 remote.getGlobal('process') 可是有緩存

shell 模塊

使用系統默認應用管理文件和 URL,並且在主進程和渲染進程中均可以用到該模塊。在菜單中,我想點擊子菜單打開一個網站,那麼就能夠用到 shell.openExternal() 方法,則會在默認瀏覽器中打開 URL

const {shell} = require('electron');
shell.openExternal('https://github.com/lin-xin/calculator');

打包應用

其實將程序打包成桌面應用纔是比較麻煩的事。我這裏嘗試了 electron-packager 和 electron-builder。

electron-packager

electron-packager 能夠將項目打包成各平臺可直接運行的程序,而不是安裝包。

先使用 npm 安裝: npm install electron-packager -S

運行打包命令:

electron-packager ./ 計算器 --platform=win32 --overwrite --icon=./icon.ico

打包會把項目文件包括 node_modules 也一塊兒打包進去,固然能夠經過 --ignore=node_modules 來忽略文件,可是若是項目中有用到第三方庫,忽略的話則找不到文件報錯了。

正確的作法就是嚴格區分 dependencies 和 devDependencies,打包的時候只會把 dependencies 的庫打包,而使用 cnpm 安裝的會有一大堆 .0.xx@xxx 的文件,也會被打包,因此最好不要用 cnpm

electron-builder

electron-builder 是基於 electron-packager 打包出來的程序再作安裝處理,將項目打包成安裝文件。

安裝:npm install electron-builder -S

打包:electron-builder --win

打包過程當中,第一次下載 electron 可能會出現鏈接超時,可使用 yarn 試試。還有 winCodeSign 和 nsis-resources 也可能會失敗,能夠參考 electron-builder/issues 解決。

總結

Electron 用起來仍是相對容易的,能夠建立個簡單的桌面應用,只是打包的過程比較容易遇到問題,網上好像也有一鍵打包的工具,沒嘗試過。以上也都是基於 windows 7 的實踐,畢竟沒有 Mac 搞不了。

更多文章:linxin/blog

相關文章
相關標籤/搜索