Electron入門教程

66CCFF發表於2019-03-11

原文連結:Electron入門教程

Electron是由Github開發,用HTML,CSS和JavaScript來構建跨平臺桌面應用程式的一個開源庫。 Electron通過將 ChromiumNode.js合併到同一個執行時環境中,並將其打包為Mac,Windows和Linux系統下的應用來實現這一目的。

相信大部分前端同學都聽說或者瞭解過NodeJs 它是一個基於Chrome V8 引擎的JavaScript執行時, 而 Chromium 是Google為發展自家瀏覽器Chrome而開啟的開源瀏覽器專案,可以看成是是Chrome的先行版。大家較為熟悉的VS Code 和 Atom就是使用Electron來完成的。

從開發的角度來看, Electron application 本質上是一個 Node. js 應用程式。可以讓前端開發者讓你使用純 JavaScript 呼叫豐富的原生作業系統APIs來創造桌面應用~

Quick Start

確認你的網路可以訪問github , 若訪問受限參考 安裝指南 來了解如何用代理、映象和自定義快取

你肯定已經已經安裝好git和node了,那麼只要:

# 官網已經有 electron-quick-start 倉庫克隆下來
git clone https://github.com/electron/electron-quick-start
# 進入資料夾
cd electron-quick-start
# 安裝依賴包並執行
npm install && npm start
複製程式碼

然後你的第一個桌面應用就開啟了!

Electron入門教程

若你跟著一起實踐到這裡,肯定會發現介面有些許不同?我這裡多了個除錯介面,那麼來看下程式碼看看。在Electron中main.js是入口檔案:

//main.js
const { app, BrowserWindow } = require('electron')

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win

function createWindow () {
  // 建立瀏覽器視窗。
  win = new BrowserWindow({ width: 800, height: 600 })

  // 然後載入應用的 index.html。對應的index.html 就是初始介面。
  win.loadFile('index.html')

  // 開啟開發者工具
  win.webContents.openDevTools()

  //關於win 視窗的生命週期我們之後再研究……
  // 當 window 被關閉,這個事件會被觸發。
  win.on('closed', () => {
    // 取消引用 window 物件,如果你的應用支援多視窗的話,
    // 通常會把多個 window 物件存放在一個陣列裡面,
    // 與此同時,你應該刪除相應的元素。
    win = null
  })
}
//關於 app 主程式的生命週期我們之後再研究……
// Electron 會在初始化後並準備
// 建立瀏覽器視窗時,呼叫這個函式。
// 部分 API 在 ready 事件觸發後才能使用。
app.on('ready', createWindow)

// 當全部視窗關閉時退出。
app.on('window-all-closed', () => {
  // 在 macOS 上,除非使用者用 Cmd + Q 確定地退出,
  // 否則絕大部分應用及其選單欄會保持啟用。
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('activate', () => {
  // 在macOS上,當單擊dock圖示並且沒有其他視窗開啟時,
  // 通常在應用程式中重新建立一個視窗。
  if (win === null) {
    createWindow()
  }
})

// 在這個檔案中,你可以續寫應用剩下主程式程式碼。
// 也可以拆分成幾個檔案,然後用 require 匯入。

複製程式碼

與現有React工程結合

迫於不會Vue ,在這裡介紹下React工程如何和Electron結合起來。

偷懶就直接使用 create-react-app 來建立react工程:

#若已安裝 請忽略
npm install -g create-react-app
create-react-app react-electron
cd react-electron
npm start
複製程式碼

新增 Electron 配置並啟動

一、 安裝 Electron包

# 在 react-electron 目錄下安裝 Electron 包
npm install -save electron
複製程式碼

二、 新增main.js

在 react-electron 目錄下新增main.js ,直接使用上面 main.js的內容 ,然後

//win.loadFile('index.html') 這一行替換為:
win.loadFile('http://localhost:3000/')
複製程式碼

這樣就將入口介面指定到react的初始介面了。

三、 啟動Electron!

修改 package.json ,新增 main homepage欄位,並新增electron-start命令:

  "main": "main.js",
  "homepage":".",

  "scripts": {
    "start": "react-scripts start",
    "build": "react-scriptsbuild",
    "test": "react-scripts test --env=jsdom",
    "eject": "react-scripts  eject",
    "electron": "electron ."
  },
}
複製程式碼

啟動 Electron:

# 啟動react專案
npm start
# 啟動electron
npm run electron
複製程式碼

Electron入門教程

看到一篇 文章 CREATE AN APP WITH ELECTRON AND REACT 寫create-react-app和Electron結合的不錯,大家也可以參考這個。

四、在react中使用electron

直接在react中使用import electron會產生問題 issues/7300,可以寫成這種形式:

const electron = window.require('electron');
const fs = electron.remote.require('fs');
const ipcRenderer  = electron.ipcRenderer;
複製程式碼

主程式和渲染程式

Electron 與web應用的區別不是很大,在原web應用的基礎上新增主執行緒互動程式碼後,甚至可以將一個線上web應用迅速的包裝成為一個客戶端應用! Electron並且內整合了 Nodejs,Nodejs 在主程式和渲染程式中都可以使用,這為我們提供了npm成千上萬的模組。

所以個人感覺應用Electron的重要在於理解主程式和渲染程式,和程式間的互動。其他API可以自己花點時間閱讀文件。

執行Electron入口檔案的程式(也就是上文執行main.js的程式)被稱為主程式,它控制著整個 App 的生命週期,從開啟到關閉。 它也管理著系統原生元素比如選單,選單欄,Dock 欄,托盤等。 主程式負責建立 APP 的每個渲染程式。而且整個 Node API 都整合在裡面;

而在主程式建立的一個個web頁面(對應上文中的win視窗)也都執行著自己的程式,即渲染程式,渲染程式各自獨立,各自擁有自己的生命週期。與主程式不同的是,它能夠同時存在多個而且執行在不一樣的程式。而且它們也能夠被隱藏。在通常的瀏覽器內,網頁通常執行在一個沙盒的環境擋住並且不能夠使用原生的資源。 然而 Electron 的使用者在 Node.js 的 API 支援下可以在頁面中和作業系統進行一些低階別的互動。

程式間通訊

Electron提供了幾種通訊方式:

一 使用ipc-rendereripc-main :

ipc-renderer 和 ipc-main 非同步互動:

//在渲染程式中:
const {ipcRenderer} = require('electron')
//傳送asynchronous-message事件到主程式
ipcRenderer.send('asynchronous-message', 'ping')
//接收主程式的asynchronous-reply通知
ipcRenderer.on('asynchronous-reply', (event, arg) => {
  console.log('asynchronous-reply : args:',arg)
  const message = `Asynchronous message reply: ${arg}`
  document.getElementById('async-reply').innerHTML = message
})

//在主程式中:
const {ipcMain} = require('electron')
//接收渲染程式的asynchronous-message通知
ipcMain.on('asynchronous-message', (event, arg) => {
  //傳送asynchronous-reply事件到渲染程式
  event.sender.send('asynchronous-reply', {'ping':'pong','num':'1'})
})

複製程式碼

ipc-renderer 和 ipc-main 同步互動:

//在渲染程式中:
const {ipcRenderer} = require('electron')

const syncMsgBtn = document.getElementById('sync-msg')

syncMsgBtn.addEventListener('click', () => {
  const reply = ipcRenderer.sendSync('synchronous-message', 'ping')
  const message = `Synchronous message reply: ${reply}`
  document.getElementById('sync-reply').innerHTML = message
})
//在主程式中:
const {ipcMain} = require('electron')

ipcMain.on('synchronous-message', (event, arg) => {
  event.returnValue = 'pong'
})

複製程式碼

二 在渲染程式使用remote模組

// 在渲染程式開啟提示對話方塊
const {dialog} = require('electron').remote
dialog.showMessageBox(options, (index) => {
      ....
    })
複製程式碼

三 在主程式向渲染程式webContents傳送訊息

win.webContents.send('ping', 'whoooooooh!')
複製程式碼

四 渲染程式之間的通訊

在兩個網頁(渲染程式)間共享資料最簡單的方法是使用瀏覽器中已經實現的 HTML5 API。 其中比較好的方案是用 Storage API, localStorage,sessionStorage 或者 IndexedDB。

你還可以用 Electron 內的 IPC 機制實現。將資料存在主程式的某個全域性變數中,然後在多個渲染程式中使用 remote 模組來訪問它。

// 在主程式中
global.sharedObject = {
  someProperty: 'default value'
}
// 在第一個頁面中
require('electron').remote.getGlobal('sharedObject').someProperty = 'new value'
// 在第二個頁面中
console.log(require('electron').remote.getGlobal('sharedObject').someProperty)
複製程式碼