主頁 > 移動端開發 > 入門Electron,手把手教你撰寫完整實用案例

入門Electron,手把手教你撰寫完整實用案例

2021-08-10 08:00:29 移動端開發

Electron簡介

Electron是干什么的? 簡單來講,Electron 使用 JavaScript,HTML 和 CSS,來構建跨平臺的桌面應用程式,

按照官方的說法:如果你可以建一個網站,你就可以建一個桌面應用程式,

和傳統的桌面應用相比,使用Electron開發更容易上手,開發效率更高,并且,web技術應用廣泛、生態繁榮,Electron可以使用幾乎所有的Web生態領域及Node.js生態領域的組件和技術方案,

與網頁應用相比,Electron基于Chromium 和 Node.js,可以避免令人頭痛的瀏覽器兼容問題,而Web前端受限訪問的檔案系統、系統托盤、系統通知等,開發Electron應用時可以自由地使用,

簡單理解Electron作業機制

使用Electron開發的桌面應用,類似于簡易版的、定制版的Chrome瀏覽器,當然這個瀏覽器中的頁面不能通過輸入網址打開,而是由開發者寫好的,

image.png
和瀏覽器架構類似,Electron應用程式區分主行程和渲染行程,

主行程負責控制應用程式的生命周期、創建和管理應用程式視窗,有著多種控制原生桌面功能的模塊,例如選單、對話框以及托盤圖示,

渲染行程負責完成渲染界面、接收用戶輸入、回應用戶的互動等作業,

一個Electron應用只有一個主行程,但可以有多個渲染行程,

在之前的文章中,我們有講過瀏覽器中的行程,可略作參考,

案例入門

下面我們將從一個任務管理的案例入門,了解electron的整體開發流程和一些基本的細節知識,

案例效果

mainWindow.gif

功能分析:

1、記錄待完成任務和已完成任務

2、通過新建,添加待完成任務,并設定時間

3、點擊完成任務,跳轉到已完成界面;點擊洗掉,可以洗掉任務

4、點擊右上角的 × 按鈕,可以關閉主界面,要再次打開主界面,可以通過系統托盤

5、設定的時間到了,會在右下角彈出提醒框,如下圖所示,

image.png

初始化專案

專案是由原生js開發,在后面的文章中,我們會再探討electron和vue、react這些前端框架的結合,

mkdir tasky
cd tasky
npm init

安裝electron

npm install electron --S

創建一個hello world應用程式

(1)第一步,在專案根目錄下,創建index.js,作為應用程式的入口檔案,因為Electron是基于Node.js,所以入口檔案使用Node.js語法,內容如下:

//引入兩個模塊:app 和 BrowserWindow

//app 模塊,控制整個應用程式的事件生命周期,
//BrowserWindow 模塊,它創建和管理程式的視窗,

const { app, BrowserWindow } = require('electron')

//在 Electron 中,只有在 app 模塊的 ready 事件被激發后才能創建瀏覽器視窗
app.on('ready', () => {

  //創建一個視窗
  const mainWindow = new BrowserWindow()
  
  //視窗加載html檔案
  mainWindow.loadFile('./src/main.html')
})

(2)第二步,創建視窗需要加載的html檔案,

為了方便后面的檔案管理,我們新建一個 src 檔案夾,用于存放web頁面資源,比如html、css、js、圖片等,

// ./src/main.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  hello world
</body>
</html>

(3)啟動程式,

修改package.jsonscripts,如下:

image.png

然后在專案根目錄運行:npm run start

這樣我們的hello world應用程式就跑起來了,入門Electron,就是這么簡單!

image.png

簡單的基礎除錯

1、主行程運行時的一些提示資訊會在命令列顯示,比如,在index.js加入console.log

app.on('ready', () => {
  console.log('just test console.log')
  const mainWindow = new BrowserWindow()
  mainWindow.loadFile('./src/main.html')
})

就可以在命令列看到列印的值:

image.png

index.js中的內容發生改變,默認要手動重啟,比較麻煩,這里我們加入nodemon,它可以監控node.js 源代碼的變化,并自動重啟應用,

安裝: npm i nodemon --D

修改scripts"start": "nodemon --watch index.js --exec electron ."

再次運行npm run start,當index.js內容變化時,就會自動重新執行electron .來重啟應用,

2、視窗頁面的除錯方法和chrome瀏覽器類似,點擊選單欄的View --- Toggle Developer Tools,或者按它對應的快捷鍵,就會出現我們熟悉的開發者工具界面,

image.png

當頁面內容發生變化,可以點擊View --- Reload,或者快捷鍵ctrl+r,重繪頁面內容,頁面熱更新會后續講到,

開始coding

專案目錄結構如下,其中src檔案夾存放的就是web頁面相關的內容,

image.png
專案有兩個視窗:主視窗和提醒視窗,在主視窗中管理任務,當任務設定時間到,會在螢屏右下角出現提醒視窗,

應用不涉及服務端資料,任務資料主要使用localStorage來存盤,

創建主視窗:

const iconPath = path.join(__dirname, './src/img/icon.png')   //應用運行時的標題欄圖示
let mainWindow
app.on('ready', () => {
  mainWindow = new BrowserWindow({
    resizable: false,   //不允許用戶改變視窗大小
    width: 800,        //設定視窗寬高
    height: 600,
    icon: iconPath,     //應用運行時的標題欄圖示
    webPreferences:{    
      backgroundThrottling: false,   //設定應用在后臺正常運行
      nodeIntegration:true,     //設定能在頁面使用nodejs的API
      contextIsolation: false,
      preload: path.join(__dirname, './preload.js')
    }
  })
  mainWindow.loadURL(`file://${__dirname}/src/main.html`)
}

main.html的內容很簡單,有興趣的童鞋可以去看原始碼,這里就不貼了,

image.png

默認Electron應用頂部有標題欄和選單欄,縱觀各個桌面應用程式,基本都是定制的頂部控制區域,對于我們這個應用,暫時只要一個關閉按鈕,所以我們將去掉這一部分,將視窗關閉按鈕寫在main.html頁面中,

無邊框視窗

要創建無邊框視窗,只需在 BrowserWindow 的 options 中將 frame 設定為 false:

mainWindow = new BrowserWindow({
   frame: false,
   ...
})

標題欄和選單欄消失了,但也會有幾個問題:

1、雖然選單欄消失了,但是依然可以通過快捷鍵進行選單操作,比如ctrl+shift+i打開開發者工具,為避免這種情況,我們需要去掉選單欄:

mainWindow.removeMenu()

2、默認情況下,無邊框視窗是不可拖拽的,應用程式需要在 CSS 中指定 -webkit-app-region: drag 來告訴 Electron 哪些區域是可拖拽的,

html,body {
  height: 100%;
  width: 100%;
}

body{
  -webkit-app-region: drag;
}

如果用上面的屬性使整個視窗都可拖拽,則必須將其中的按鈕標記為不可拖拽,否則按鈕將無法點擊,

.enable-click {
  -webkit-app-region: no-drag;
}

3、當點擊自定義的視窗關閉按鈕,我們并不希望退出程式,只是將視窗隱藏,可以通過系統托盤再次打開視窗,
image.png

系統托盤

程式啟動時,將應用程式加入系統托盤,在Electron中,借助Tray模塊實作,

const { app, BrowserWindow, Tray, Menu } = electron
const iconPath = path.join(__dirname, './src/img/icon.png')
let mainWindow, tray
app.on('ready', () => {
  mainWindow = new BrowserWindow({
    //... options
  })
  mainWindow.loadURL(`file://${__dirname}/src/main.html`)
  
  tray = new Tray(iconPath)      //實體化一個tray物件,建構式的唯一引數是需要在托盤中顯示的圖示url  
  
  tray.setToolTip('Tasky')       //滑鼠移到托盤中應用程式的圖示上時,顯示的文本
  
  tray.on('click', () => {       //點擊圖示的回應事件,這里是切換主視窗的顯示和隱藏
    if(mainWindow.isVisible()){
      mainWindow.hide()
    }else{
      mainWindow.show()
    }
  })
  
  tray.on('right-click', () => {    //右鍵點擊圖示時,出現的選單,通過Menu.buildFromTemplate定制,這里只包含退出程式的選項,
    const menuConfig = Menu.buildFromTemplate([
      {
        label: 'Quit',
        click: () => app.quit()
      }
    ])
    tray.popUpContextMenu(menuConfig)
  })

})

IPC通信

回到上一個問題,點擊頁面內的按鈕怎樣隱藏視窗?這就需要用到IPC通信了,

image.png
IPC(Inter-Process Communication),就是行程間通信,Electron應用程式區分主行程和渲染行程,有時候,兩者之間需要通信,傳輸一些資料、發送一些訊息,

渲染行程 TO 主行程

比如,點擊關閉按鈕,就需要渲染行程向主行程發送隱藏主視窗的請求,

渲染行程使用Electron內置的ipcRenderer模塊向主行程發送訊息,ipcRenderer.send方法的第一個引數是訊息管道名稱,

//頁面的js代碼:
const electron = require('electron')
const { ipcRenderer } = electron

closeDom.addEventListener('click', () => {
  ipcRenderer.send('mainWindow:close')
})

主行程通過ipcMain接收訊息,ipcMain.on方法的第一個引數也為訊息管道的名稱,與ipcRenderer.send的名稱對應,第二個引數是接收到訊息的回呼函式,

//入口檔案index.js
ipcMain.on('mainWindow:close', () => {
  mainWindow.hide()
})

主行程 TO 渲染行程

主行程向渲染行程發送訊息是通過渲染行程的webContents,在mainWindow渲染行程設定了任務后,會傳輸給主行程任務資訊,當任務時間到了,主行程會創建提醒視窗remindWindow,并通過remindWindow.webContents將任務名稱發給remindWindow

function createRemindWindow (task) {
 
  remindWindow = new BrowserWindow({
     //options
  })
  remindWindow.loadURL(`file://${__dirname}/src/remind.html`)
  
  //主行程發送訊息給渲染行程
  remindWindow.webContents.send('setTask', task)

}

remindWindow渲染行程中,通過ipcRenderer.on接受訊息,

ipcRenderer.on('setTask', (event,task) => {
   document.querySelector('.reminder').innerHTML = 
      `<span>${decodeURIComponent(task)}</span>的時間到啦!`
})

image.png

渲染行程 TO 渲染行程

渲染行程之間傳遞訊息,可以通過主行程中轉,即視窗A先把訊息發送給主行程,主行程再把這個訊息發送給視窗B,這種非常常見,

也可以從視窗A直接發訊息給視窗B,前提是視窗A知道視窗B的webContents的id,

ipcRenderer.sendTo(webContentsId, channel, ...args)

值得注意的是,我們在頁面的js代碼中使用了require,這也是Electron的一大特點,在渲染行程中可以訪問Node.js API,這樣做的前提是在創建視窗時配置webPreferencesnodeIntegration: truecontextIsolation: false

mainWindow = new BrowserWindow({
    width: 800,
    height: 600,
    webPreferences:{
      nodeIntegration: true,
      contextIsolation: false
    }
  })

視窗位置

當任務時間到,提醒視窗會在螢屏右下角出現,怎樣設定視窗位置呢?

function createRemindWindow (task) {
  //創建提醒視窗
  remindWindow = new BrowserWindow({
    //...options
  })
  
  //獲取螢屏尺寸
  const size = screen.getPrimaryDisplay().workAreaSize
  
  //獲取托盤位置的y坐標(windows在右下角,Mac在右上角)
  const { y } = tray.getBounds()
  
  //獲取視窗的寬高
  const { height, width } = remindWindow.getBounds()
  
  //計算視窗的y坐標
  const yPosition = process.platform === 'darwin' ? y : y - height
  
  //setBounds設定視窗的位置
  remindWindow.setBounds({
    x: size.width - width,     //x坐標為螢屏寬度 - 視窗寬度
    y: yPosition,
    height,
    width 
  })
  
  //當有多個應用時,提醒視窗始終處于最上層
  remindWindow.setAlwaysOnTop(true)
  
  remindWindow.loadURL(`file://${__dirname}/src/remind.html`)
}

關閉視窗

提醒視窗會在一段時間后關閉,可以通過remindWindow.close()來關閉視窗,

當視窗關閉后,我們可以設定remindWindow = null來回收分配給該渲染行程的資源,

remindWindow.on('closed', () => { remindWindow = null })

結語

這篇文章主要是介紹electron的一些基礎知識,下一篇文章,我們將探討electron的打包問題,下次見,

凡能用JavaScript實作的,注定會被用JavaScript實作,        
                                               ---Jeff Atwood

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/292752.html

標籤:其他

上一篇:手把手教你搭建應用的網路診斷模塊(1)——Ping與TraceRoute

下一篇:AIDL入門學習二

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more