Electron構建跨平臺應用Mac/Windows/Linux

Poetries發表於2019-03-03

本文面向新人、沒有接觸過Electron的同學,做了一些基礎的知識梳理,助你快速入門。

一、前言

  • NW.jsElectron 都可以用前端的知識來開發桌面應用。NW.jsElectron起初是同一 個作者開發。後來種種原因分為兩個產品。一個命名為 NW.js(英特爾公司提供技術支援)、 另一命名為 Electron(Github 公司提供技術支援)。
  • NW.jsElectron 可以用 Nodejs 中幾乎所有的模組。NW.jsElectron不僅可以把 html 寫的 web 頁面打包成跨平臺可以安裝到電腦上面的軟體,也可以通過 javascript 訪問操作 系統原生的 UIApi(控制視窗、新增選單專案、托盤應用選單、讀寫檔案、訪問剪貼簿)。

githubatom 編輯器、微軟的 vscode 編輯器,包括阿里內部的一些 軟體也是用 electron 開發的

1. Electron 是由誰開發的?

Electron 是由 Github 開發

2. Electron 是什麼?

Electron 是一個用 HTMLCSSJavaScript 來構建跨平臺桌面應用程式的一個開源庫

3. Electron 把 HTML,CSS 和 JavaScript 組合的程式構建為跨平臺桌面應用程式的原理 是什麼?

原理為 Electron 通過將 ChromiumNode.js 合併到同一個執行時環境中,並將其打包為 MacWindowsLinux 系統下的應用來實現這一目的。

4. Electron 何時出現的,為什麼會出現?

Electron2013 年作為構建 Atom 的框架而被開發出來。這兩個專案在 2014 春季開源。 (Atom:為 Github 上可程式設計的文字編輯器)

一些歷史:

  • 20134Atom Shell 專案啟動 。
  • 20145Atom Shell 被開源 。
  • 20154Atom Shell 被重新命名為 Electron
  • 20165Electron 釋出了 v1.0.0 版本

5. Electron 當前流行程度?

目前 Electron 已成為開源開發者、初創企業和老牌公司常用的開發工具。

6. Electron 當前由那些人在維護支援?

Electron 當前由 Github 上的一支團隊和一群活躍的貢獻者維護。有些貢獻者是獨立開發者,有些則在用 Electron 構建應用的大型公司裡工作。

7. Electron 新版本多久釋出一次?

Electron 的版本釋出相當頻繁。每當 ChromiumNode.js 有重要的 bug 修復,新 API 或是版本更新時 Electron 會發布新版本。

  • 一般 Chromium 發行新的穩定版後的一到兩週之內,ElectronChromium 的版本會對其進行更新,具體時間根據升級所需的工作量而定。 一般 Node.js 發行新的穩定版一個月後,ElectronNode.js 的版本會對其進行更新,具 體時間根據升級所需的工作量而定。

8. Electron 的核心理念是什麼?

Electron 的核心理念是:保持 Electron 的體積小和可持續性開發。 如:為了保持 Electron 的小巧 (檔案體積) 和可持續性開發 (以防依賴庫和 API 的泛濫) , Electron 限制了所使用的核心專案的數量。 比如 Electron 只用了 Chromium 的渲染庫而不是其全部元件。這使得升級 Chromium 更加容易,但也意味著 Electron 缺少了 Google Chrome 裡的一些瀏覽器相關的特性。 新增到 Electron 的新功能應該主要是原生 API。 如果可以的話,一個功能應該儘可能的成 為一個 Node.js 模組。

9. Electron 當前的最新版本為多少?

Electron 當前的最新版本為 4.0.1 (當前時間為 201916 號)

二、環境搭建

1. 安裝 electron

npm install -g electron
複製程式碼

2. 克隆一個倉庫、快速啟動一個專案

# 克隆示例專案的倉庫
git clone https://github.com/electron/electron-quick-start

# 進入這個倉庫
cd electron-quick-start

# 安裝依賴並執行
npm install && npm start
複製程式碼

3. 手動搭建一個 electron 專案

  1. 新建一個專案目錄 例如: electrondemo01
  2. electrondemo01 目錄下面新建三個檔案: index.htmlmain.jspackage.json
  3. index.html 裡面用 css 進行佈局(以前怎麼寫現在還是怎麼寫)
  4. main.js 中寫如下程式碼
var electron =require('electron'); //electron 物件的引用
const app=electron.app; //BrowserWindow 類的引用
const BrowserWindow=electron.BrowserWindow;

let mainWindow=null; //監聽應用準備完成的事件 app.on('ready',function(){

//監聽應用準備完成的事件
app.on('ready',function(){
    //建立視窗
    mainWindow=new BrowserWindow({width: 800, height: 600}); mainWindow.loadFile('index.html');
    
    mainWindow.on('closed', function () {
        mainWindow = null; })
    })
})

//監聽所有視窗關閉的事件 
app.on('window-all-closed', function () {
    // On OS X it is common for applications and their menu bar // to stay active until the user quits explicitly with Cmd + Q 
    if (process.platform !== 'darwin') {
        app.quit(); 
    }
})
複製程式碼
  1. 執行
electron . #注意:命令後面有個點
複製程式碼

4. electron-forge 搭建一個 electron 專案

electron-forge 相當於 electron 的一個腳手架,可以讓我們更方便的建立、執行、打包 electron 專案

npm install -g electron-forge 

electron-forge init my-new-app 

cd my-new-app

npm start
複製程式碼

三、Electron 執行流程

3.1 Electron 執行的流程

image.png

3.2 Electron 主程式和渲染程式

  • Electron 執行 package.jsonmain 指令碼的程式被稱為主程式。
  • 在主程式中執行的指令碼通過建立 web 頁面來展示使用者介面。 一個 Electron 應用總是有且只有一個主程式。
  • 由於 Electron 使用了 Chromium(谷歌瀏覽器)來展示 web 頁面,所以 Chromium 的 多程式架構也被使用到。 每個 Electron 中的 web 頁面執行在它自己的渲染程式中。
  • 主程式使用 BrowserWindow 例項建立頁面。每個 BrowserWindow 例項都在自己的渲 染程式裡執行頁面。 當一個 BrowserWindow例項被銷燬後,相應的渲染程式也會被終止

image.png

image.png

  • 程式:程式是計算機中的程式關於某資料集合上的一次執行活動,是 系統進行資源分配和排程的基本單位,是作業系統結構的基礎。
  • 執行緒:在一個程式裡的一個執行路線就叫做執行緒(thread)。更準確的定義是: 執行緒是“一個程式內部的控制序列”。
  • 執行緒和程式:一個程式至少有一個程式,一個程式至少有一個執行緒

3.3 Electron 渲染程式中通過 Nodejs 讀取本地檔案

在普通的瀏覽器中,web頁面通常在一個沙盒環境中執行,不被允許去接觸原生的資源。 然而 Electron 的使用者在 Node.jsAPI支援下可以在頁面中和作業系統進行一些底層交 互。 Nodejs 在主程式和渲染程式中都可以使用。渲染程式因為安全限制,不能直接操作生 GUI。雖然如此,因為整合了 Nodejs,渲染程式也有了作業系統底層 API的能力,Nodejs 中常用的 PathfsCrypto 等模組在 Electron 可以直接使用,方便我們處理連結、路徑、 檔案 MD5 等,同時 npm 還有成千上萬的模組供我們選擇。

var fs = require('fs');
var content = document.getElementById('content'); 
var button = document.getElementById('button');

button.addEventListener('click',function(e){
    fs.readFile('package.json','utf8',function(err,data){ 
        content.textContent = data;
        console.log(data);
    }); 
});
複製程式碼

3.4 Electron 開啟除錯模式

 mainWindow.webContents.openDevTools();
複製程式碼

image.png

四、Electron 模組介紹

Electron 模組介紹、remote 模組、通 過 BrowserWindow 開啟新視窗

4.1 Electron 主程式和渲染程式中的模組

image.png

4.2 Electron remote 模組

remote 模組提供了一種在渲染程式(網頁)和主程式之間進行程式間通訊(IPC)的簡便途徑

Electron 中, 與 GUI 相關的模組(如 dialog, menu 等)只存在於主程式,而不在渲染程式中 。為了能從渲染程式中使用它們,需要用ipc模組來給主程式傳送程式間訊息。使用 remote 模組,可以呼叫主程式物件的方法,而無需顯式地傳送程式間訊息,這類似於 JavaRMI

4.3 通過BrowserWindow 開啟新視窗

Electron 渲染程式中通過 remote 模組呼叫主程式中的 BrowserWindow 開啟新視窗

electronjs.org/docs/api/br…

// 主程式程式碼


const electron = require('electron'); 

// 控制應用生命週期的模組 
const {app} = electron;

// 建立本地瀏覽器視窗的模組 
const {BrowserWindow} = electron;

// 指向視窗物件的一個全域性引用,如果沒有這個引用,那麼當該 javascript 物件被垃圾回收 的
// 時候該視窗將會自動關閉
let win;

function createWindow() {
    // 建立一個新的瀏覽器視窗
    win = new BrowserWindow({width: 1104, height: 620});//570+50
    
    // 並且裝載應用的 index.html 頁面
    win.loadURL(`file://${__dirname}/html/index.html`);
    
    // 開啟開發工具頁面
    win.webContents.openDevTools();
    
    //當視窗關閉時呼叫的方法
    win.on('closed', () => {
        // 解除視窗物件的引用,通常而言如果應用支援多個視窗的話,你會在一個陣列裡 // 存放視窗物件,在視窗關閉的時候應當刪除相應的元素。
        win = null;
    });
}

// 當 Electron 完成初始化並且已經建立了瀏覽器視窗,則該方法將會被呼叫。
// 有些 API 只能在該事件發生後才能被使用
app.on('ready', createWindow);

// 當所有的視窗被關閉後退出應用 
app.on('window-all-closed', () => {
    // 對於 OS X 系統,應用和相應的選單欄會一直啟用直到使用者通過 Cmd + Q 顯式退出 
    if (process.platform !== 'darwin') {
        app.quit(); 
    }
});


app.on('activate', () => {
    // 對於 OS X 系統,當 dock 圖示被點選後會重新建立一個 app 視窗,並且不會有其他
    // 視窗開啟
    if (win === null) {
        createWindow(); 
    }
});

// 在這個檔案後面你可以直接包含你應用特定的由主程式執行的程式碼。 
// 也可以把這些程式碼放在另一個檔案中然後在這裡匯入
複製程式碼
// 渲染程式程式碼 /src/render/index.js
// 開啟新視窗屬性用法有點類似vscode開啟新的視窗

const btn = document.querySelector('#btn');
const path = require('path');
const BrowerWindow = require('electron').remote.BrowserWindow;

btn.onclick = () => {
    win = new BrowerWindow({ 
        width: 300,
        height: 200, 
        frame: false, // false隱藏關閉按鈕、選單選項 true顯示
        fullscreen:true, // 全屏展示
        transparent: true 
    }) 

    win.loadURL(path.join('file:',__dirname,'news.html'));

    win.on('close',()=>{win = null});
}
複製程式碼

image.png

五、自定義頂部選單/右鍵選單

image.png

5.1 主程式中呼叫Menu模組-自定義軟體頂部選單

electronjs.org/docs/api/me…

ElectronMenu 模組可以用來建立原生選單,它可用作應用選單和 context 選單

這個模組是一個主程式的模組,並且可以通過 remote 模組給渲染程式呼叫

// main/menu.js
const { Menu }  = require('electron')

// 文件 https://electronjs.org/docs/api/menu-item
// 選單專案
let menus = [
    {
        label: '檔案',
        submenu: [
            {
                label: '新建檔案',
                accelerator: 'ctrl+n', // 繫結快捷鍵
                click: function () { // 繫結事件
                    console.log('新建檔案')
                }
            },
            {
                label: '新建視窗',
                click: function () {
                    console.log('新建視窗')
                }
            }
        ]
    },
    {
        label: '編輯',
        submenu: [
            {
                label: '複製',
                role: 'copy' // 呼叫內建角色實現對應功能
            },
            {
                label: '剪下',
                role: 'cut'  // 呼叫內建角色實現對應功能
            }
        ]
    },
    {
        label: '檢視',
        submenu: [
            {
                label: '瀏覽'
            },
            {
                label: '搜尋'
            }
        ]
    }
]

let m = Menu.buildFromTemplate(menus)
Menu.setApplicationMenu(m)
複製程式碼
// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/menu.js')
};

複製程式碼

image.png

我們給選單繫結事件,在命令列控制檯可以看到

image.png

5.2 渲染程式中呼叫Menu模組

不推薦使用這種方式,建議在主程式中使用

1. remote

通過remote呼叫主程式的方法

// 選單引入的方式發生變化
const { Menu }  = require('electron').remote

// 其他程式碼和上面選單一樣
// ...
複製程式碼

2. 加入index.html

<script src="render/menu.js"></script>
複製程式碼

5.3 渲染程式中自定義右鍵選單

1. 定義選單

// render/menu.js

// 在渲染程式中通過remote模組呼叫主程式中的模組
const { Menu }  = require('electron').remote
const { remote } = require('electron')

// 文件 https://electronjs.org/docs/api/menu-item
// 選單專案
let menus = [
    {
        label: '檔案',
        submenu: [
            {
                label: '新建檔案',
                accelerator: 'ctrl+n', // 繫結快捷鍵
                click: function () { // 繫結事件
                    console.log('新建檔案')
                }
            },
            {
                label: '新建視窗',
                click: function () {
                    console.log('新建視窗')
                }
            }
        ]
    },
    {
        label: '編輯',
        submenu: [
            {
                label: '複製',
                role: 'copy' // 呼叫內建角色實現對應功能
            },
            {
                label: '剪下',
                role: 'cut'  // 呼叫內建角色實現對應功能
            }
        ]
    },
    {
        label: '檢視',
        submenu: [
            {
                label: '瀏覽'
            },
            {
                label: '搜尋'
            }
        ]
    }
]

let m = Menu.buildFromTemplate(menus)
// Menu.setApplicationMenu(m)

// 繫結右鍵選單
window.addEventListener('contextmenu', (e)=>{
   e.preventDefault()
   m.popup({
    window: remote.getCurrentWindow()
   })
}, false)
複製程式碼

image.png

2. 引入

<!--index.html-->
<script src="render/menu.js"></script>
複製程式碼

六、程式通訊

image.png

6.1 主程式與渲染程式之間的通訊

有時候我們想在渲染程式中通過一個事件去執行主程式裡面的方法。或者在渲染程式中通知 主程式處理事件,主程式處理完成後廣播一個事件讓渲染程式去處理一些事情。這個時候就 用到了主程式和渲染程式之間的相互通訊

Electron 主程式,和渲染程式的通訊主要用到兩個模組:ipcMainipcRenderer

  • ipcMain:當在主程式中使用時,它處理從渲染器程式(網頁)傳送出來的非同步和同步資訊,當然也有可能從主程式向渲染程式傳送訊息。
  • ipcRenderer: 使用它提供的一些方法從渲染程式 (web 頁面) 傳送同步或非同步的訊息到主程式。 也可以接收主程式回覆的訊息

6.1.1 渲染程式給主程式傳送非同步訊息

間接實現渲染程式執行主程式裡面的方法

1. 引入ipcRender

<!--src/index.html-->
<button id="send">在 渲染程式中執行主程式裡的方法(非同步)</button>
<script src="render/ipcRender.js"></script>
複製程式碼

2. 引入ipcMain

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain.js')
};
複製程式碼

3. 渲染程式傳送訊息

// src/render/ipcRender.js
//渲染程式

let send = document.querySelector('#send');
const { ipcRenderer } = require('electron');

send.onclick = function () {
    // 傳遞訊息給主程式
    // 非同步
    ipcRenderer.send('sendMsg', {name:'poetries', age: 23})
}
複製程式碼

2. 主程式接收訊息

// src/main/ipcMain.js

//主程式

const { ipcMain }  = require('electron')

// 主程式處理渲染程式廣播資料
ipcMain.on('sendMsg', (event, data)=> {
    console.log('data\n ', data)
    console.log('event\n ', event)
})
複製程式碼

image.png

6.1.2 渲染程式傳送訊息,主程式接收訊息並反饋

渲染程式給主程式傳送非同步訊息,主程式接收到非同步訊息以後通知渲染程式

1. 引入ipcRender

<!--src/index.html-->
<button id="sendFeedback">在 渲染程式中執行主程式裡的方法,並反饋給主程式(非同步)</button>
<script src="render/ipcRender.js"></script>
複製程式碼

2. 引入ipcMain

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain.js')
};
複製程式碼

3. 渲染程式傳送訊息

// src/render/ipcRender.js

//渲染程式
let sendFeedback = document.querySelector('#sendFeedback');

const { ipcRenderer } = require('electron');

// 向主程式傳送訊息
sendFeedback.onclick = function () {
    // 觸發主程式裡面的方法
    ipcRenderer.send('sendFeedback', {name:'poetries', age: 23})
}
複製程式碼

4. 主程式收到訊息處理並廣播反饋通知渲染程式

// src/main/ipcMain.js

//主程式
const { ipcMain }  = require('electron')


// 主程式處理渲染程式廣播資料,並反饋給渲染程式
ipcMain.on('sendFeedback', (event, data)=> {
    // console.log('data\n ', data)
    // console.log('event\n ', event)
    
    // 主程式給渲染程式廣播資料
    event.sender.send('sendFeedbackToRender', '來自主程式的反饋')
})
複製程式碼

5. 渲染程式處理主程式廣播的資料

// src/render/ipcRender.js
// 向主程式傳送訊息後,接收主程式廣播的事件
ipcRenderer.on('sendFeedbackToRender', (e, data)=>{
    console.log('event\n ', e)
    console.log('data\n ', data)
})
複製程式碼

image.png

6.1.3 渲染程式給主程式傳送同步訊息

1. 引入ipcRender

<!--src/index.html-->
 <button id="sendSync">渲染程式和主程式同步通訊</button>
<script src="render/ipcRender.js"></script>
複製程式碼

2. 引入ipcMain

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain.js')
};
複製程式碼

3. 渲染程式給主程式同步通訊

// src/render/ipcMain.js
let sendSync = document.querySelector('#sendSync');

// 渲染程式和主程式同步通訊
sendSync.onclick = function () {
    // 同步廣播資料
   let msg =  ipcRenderer.sendSync('sendsync', {name:'poetries', age: 23})
    
   // 同步返回主程式反饋的資料
   console.log('msg\n ', msg)
}
複製程式碼

4. 主程式接收資料處理

// src/main/ipcMain.js

// 渲染程式和主程式同步通訊 接收同步廣播
ipcMain.on('sendsync', (event, data)=> {
    // console.log('data\n ', data)
    // console.log('event\n ', event)
    // 主程式給渲染程式廣播資料
    event.returnValue ='渲染程式和主程式同步通訊 接收同步廣播,來自主程式的反饋.';
})
複製程式碼

image.png

6.1.4 渲染程式廣播通知主程式開啟視窗

一般都是在渲染程式中執行廣播操作,去通知主程式完成任務

1. 引入openWindow

<!--src/index.html-->
 <button id="sendSync">渲染程式和主程式同步通訊</button>
<script src="render/openWindow.js"></script>
複製程式碼

2. 引入ipcMain2

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain2.js')
};
複製程式碼

3. 渲染程式通知主程式開啟視窗

// src/render/openWindow.js

/* eslint-disable */
let openWindow = document.querySelector('#openWindow');

var { ipcRenderer } = require('electron');

// 渲染程式和渲染程式直接的通訊========
openWindow.onclick = function () {
    // 通過廣播的形式 通知主程式執行操作
    ipcRenderer.send('openwindow', {name:'poetries', age: 23})
}
複製程式碼

4. 主程式收到通知執行操作

// src/main/ipcMain2.js

/* eslint-disable */
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')

let win;

// 接收到廣播
ipcMain.on('openwindow', (e, data)=> {
    // 呼叫window開啟新視窗
    win = new BrowserWindow({
        width: 400,
        height: 300,
    });
    win.loadURL(path.join('file:',__dirname, '../news.html'));
    win.webContents.openDevTools()
    win.on('closed', () => {
        win = null;
      });
})
複製程式碼

image.png

6.2 渲染程式與渲染程式之間的通訊

也就是兩個視窗直接的通訊

6.2.1 localstorage傳值

Electron 渲染程式通過 localstorage 給另一個渲染程式傳值

1. 引入openWindow

<!--src/index.html-->
 <button id="sendSync">渲染程式和主程式同步通訊</button>
<script src="render/openWindow.js"></script>
複製程式碼

2. 引入ipcMain2

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain2.js')
};
複製程式碼

3. 渲染程式通知主程式開啟視窗

// src/render/openWindow.js

/* eslint-disable */
let openWindow = document.querySelector('#openWindow');

var { ipcRenderer } = require('electron');

// 渲染程式和渲染程式直接的通訊========
openWindow.onclick = function () {
    // 通過廣播的形式 通知主程式執行操作
    ipcRenderer.send('openwindow', {name:'poetries', age: 23})
    
    // ======= localstorage傳值 =====
     localStorage.setItem('username', 'poetries')
}
複製程式碼

4. 新建news頁面

<!--src/news.html-->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    news page
  </body>
  <script src="render/news.js"></script>
</html>
複製程式碼
// src/render/news.js

let username = localStorage.getItem('username')
console.log(username)
複製程式碼

5. 主程式收到通知執行操作

// src/main/ipcMain2.js

/* eslint-disable */
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')

let win;

// 接收到廣播
ipcMain.on('openwindow', (e, data)=> {
    // 呼叫window開啟新視窗
    win = new BrowserWindow({
        width: 400,
        height: 300,
    });
    win.loadURL(path.join('file:',__dirname, '../news.html'));
    win.webContents.openDevTools()
    win.on('closed', () => {
        win = null;
      });
})
複製程式碼

6.2.2 BrowserWindow和webContents方式實現

通過 BrowserWindowwebContents 模組實現渲染程式和渲染程式的通訊

webContents 是一個事件發出者.它負責渲染並控制網頁,也是 BrowserWindow 物件的屬性

需要了解的幾個知識點

  1. 獲取當前視窗的 id
const winId = BrowserWindow.getFocusedWindow().id;
複製程式碼
  1. 監聽當前視窗載入完成的事件
win.webContents.on('did-finish-load',(event) => {
    
})
複製程式碼
  1. 同一視窗之間廣播資料
win.webContents.on('did-finish-load',(event) => {
    win.webContents.send('msg',winId,'我是 index.html 的資料');
})
複製程式碼
  1. 通過 id 查詢視窗
let win = BrowserWindow.fromId(winId);
複製程式碼

下面是具體演示

1. 引入openWindow

<!--src/index.html-->
 <button id="sendSync">渲染程式和主程式同步通訊</button>
<script src="render/openWindow.js"></script>
複製程式碼

2. 引入ipcMain2

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/ipcMain2.js')
};
複製程式碼

3. 渲染程式通知主程式開啟視窗

// src/render/openWindow.js

/* eslint-disable */
let openWindow = document.querySelector('#openWindow');

var { ipcRenderer } = require('electron');

// 渲染程式和渲染程式直接的通訊========
openWindow.onclick = function () {
    // 通過廣播的形式 通知主程式執行操作
    ipcRenderer.send('openwindow', {name:'poetries', age: 23})
}
複製程式碼

4. 主程式收到通知執行操作

// src/main/ipcMain2.js

let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')

let win;

// 接收到廣播
ipcMain.on('openwindow', (e, userInfo)=> {
    // 呼叫window開啟新視窗
    win = new BrowserWindow({
        width: 400,
        height: 300,
    });
    win.loadURL(path.join('file:',__dirname, '../news.html'));

    // 新開視窗除錯模式
    win.webContents.openDevTools()

    // 把渲染程式傳遞過來的資料再次傳遞給渲染程式news
    // 等待視窗載入完
    win.webContents.on('did-finish-load', ()=>[
        win.webContents.send('toNews', userInfo)
    ])
    

    win.on('closed', () => {
        win = null;
      });
})
複製程式碼

5. news接收主程式傳遞的資料

資料經過渲染程式->主程式->news渲染程式

<!--news頁面-->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title></title>
  </head>
  <body>
    news page
  </body>
  <script src="render/news.js"></script>
</html>
複製程式碼
// src/render/news.js

var { ipcRenderer } = require('electron');

// let username = localStorage.getItem('username')
// console.log(username)

// 監聽主程式傳遞過來的資料 
ipcRenderer.on('toNews',(e, userInfo)=>{
    console.log(userInfo)
})
複製程式碼

image.png

image.png

那麼,這裡有一個問題,news程式接收到了廣播後如何給出反饋呢?

image.png

1. 在主程式中獲取視窗ID傳遞

// src/main/ipcMain2.js


let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')

let win;

// 接收到廣播
ipcMain.on('openwindow', (e, userInfo)=> {
      // 獲取當前視窗ID 放在第一行保險  因為後面也開啟了新視窗使得獲取的ID有問題
    let winId = BrowserWindow.getFocusedWindow().id

    // 呼叫window開啟新視窗
    win = new BrowserWindow({
        width: 400,
        height: 300,
    });
    win.loadURL(path.join('file:',__dirname, '../news.html'));

    // 新開視窗除錯模式
    win.webContents.openDevTools()

  

    // 把渲染程式傳遞過來的資料再次傳遞給渲染程式news
    // 等待視窗載入完
    win.webContents.on('did-finish-load', ()=>[
        win.webContents.send('toNews', userInfo, winId)
    ])
    

    win.on('closed', () => {
        win = null;
      });
})
複製程式碼

2. 在news程式中廣播資料

// src/render/news.js

var { ipcRenderer } = require('electron');

// 注意這裡 在渲染程式中需要從remote中獲取BrowserWindow
const BrowerWindow = require('electron').remote.BrowserWindow;

// let username = localStorage.getItem('username')
// console.log(username)

// 監聽主程式傳遞過來的資料 
ipcRenderer.on('toNews',(e, userInfo, winId)=>{
    // windID 第一個視窗ID
    // 獲取對應ID的視窗
    let firstWin = BrowerWindow.fromId(winId)
    firstWin.webContents.send('toIndex', '來自news程式反饋的資訊')
    console.log(userInfo)
})
複製程式碼

3. 在另一個渲染程式中處理廣播

/* eslint-disable */
let openWindow = document.querySelector('#openWindow');

var { ipcRenderer } = require('electron');

// 渲染程式和渲染程式直接的通訊========
openWindow.onclick = function () {
    // 傳遞訊息給主程式
    ipcRenderer.send('openwindow', {name:'poetries', age: 23})

    // 傳遞給開啟的視窗 渲染程式和渲染程式直接的通訊
    localStorage.setItem('username', 'poetries')
    
}

// 接收news渲染程式傳遞回來的訊息
ipcRenderer.on('toIndex', (e, data)=>{
    console.log('===', data)
})
複製程式碼

image.png

七、Electron Shell 模組

image.png

7.1 Shell 模組使用

文件 electronjs.org/docs/api/sh…

Electron Shell 模組在使用者預設瀏覽器 中開啟 URL 以及 Electron DOM webview 標籤。Shell既屬於主程式模組又是渲染程式模組

shell 模組提供了整合其他桌面客戶端的關聯功能

1. 引入

<!--index.html-->
<button id="shellDom">通過shell開啟外部連結</button>
<script src="render/shell.js"></script>
複製程式碼

2. shell.js

// src/render/shell.js

const { shell } = require('electron')
let shellDom = document.querySelector('#shellDom');

shellDom.onclick = function (e) {
   shell.openExternal('https://github.com/poetries')
}
複製程式碼

7.2 Electron DOM <webview> 標籤

Webviewiframe 有點相似,但是與 iframe 不同, webview 和你的應用執行的是不同的程式。它不擁有渲染程式的許可權,並且應用和嵌入內容之間的互動全部都是非同步的。因為這能 保證應用的安全性不受嵌入內容的影響。

<!--src/index.html中引入-->
<webview id="webview" src="http://blog.poetries.top" style="position:fixed; width:100%; height:100%">
</webview>
複製程式碼

7.3 shell模組<webview>結合Menu模組使用案例

1. 新建src/render/webview.js

/* eslint-disable */
var { ipcRenderer } = require('electron');
let myWebview = document.querySelector('#myWebview')

ipcRenderer.on('openwebview', (e, url)=>{
    myWebview.src = url
})
複製程式碼

2. 引入src/index.html

<webview id="myWebview" src="http://blog.poetries.top" style="position:fixed; width:100%; height:100%">
</webview>
    
<script src="render/webview.js"></script>
複製程式碼

3. 新建src/main/menu.js

/* eslint-disable */
const { shell, Menu, BrowserWindow } = require('electron');

// 當前視窗渲染網頁
function openWebView(url) {
    // 獲取當前視窗Id
    let win = BrowserWindow.getFocusedWindow()

    // 廣播通知渲染程式開啟webview
    win.webContents.send('openwebview', url)
}

// 在視窗外開啟網頁
function openWeb(url) {
    shell.openExternal(url)
}

let template = [
    {
        label: '幫助',
        submenu: [
            {
                label: '關於我們',
                click: function () {
                    openWeb('http://blog.poetries.top')
                }
            },
            {
                type: 'separator'
            },
            {
                label: '聯絡我們',
                click: function () {
                    openWeb('https://github.com/poetries')
                }
            }
        ]
    },
   {
        label: '載入網頁',
        submenu: [
            {
                label: '部落格',
                click: function () {
                    openWebView('http://blog.poetries.top')
                }
            },
            {
                type: 'separator' // 分隔符
            },
            {
                label: 'GitHub',
                click: function () {
                    openWebView('https://github.com/poetries')
                }
            },
            {
                type: 'separator' // 分隔符
            },
            {
                label: '簡書',
                click: function () {
                    openWebView('https://www.jianshu.com/users/94077fcddfc0/timeline')
                }
            }
        ]
   },
   {
    label: '視訊網站',
    submenu: [
        {
            label: '優酷',
            click: function () {
                openWebView('https://www.youku.com')
            }
        },
        {
            type: 'separator' // 分隔符
        },
        {
            label: '愛奇藝',
            click: function () {
                openWebView('https://www.iqiyi.com/')
            }
        },
        {
            type: 'separator' // 分隔符
        },
        {
            label: '騰訊視訊',
            click: function () {
                openWebView('https://v.qq.com/')
            }
        }
    ]
    }
]

let m = Menu.buildFromTemplate(template)
Menu.setApplicationMenu(m)
複製程式碼

4. 引入menu

// 在主程式src/index.js中引入
const createWindow = () => {

  // 建立選單  
  // 引入選單模組
  require('./main/menu.js')
};
複製程式碼

image.png

八、Electron dialog 彈出框

image.png

文件 electronjs.org/docs/api/di…

dialog屬於主程式中的模組

dialog 模組提供了 api 來展示原生的系統對話方塊,例如開啟檔案框,alert 框, 所以 web 應用可以給使用者帶來跟系統應用相同的體驗

1. 在src/index.html中引入

<button id="showError">showError</button><br />
<button id="showMsg">showMsg</button><br />
<button id="showOpenDialog">showOpenDialog</button><br />
<button id="saveDialog">saveDialog</button><br />

<script src="render/dialog.js"></script>
複製程式碼

2. 新建render/dialog.js

// render/dialog.js

let showError = document.querySelector('#showError');
let showMsg = document.querySelector('#showMsg');
let showOpenDialog = document.querySelector('#showOpenDialog');
let saveDialog = document.querySelector('#saveDialog');

var {remote} = require('electron')

showError.onclick = function () {
    remote.dialog.showErrorBox('警告', '操作有誤')
}
showMsg.onclick = function () {
    remote.dialog.showMessageBox({
        type: 'info',
        title: '提示資訊',
        message: '內容',
        buttons: ['確定', '取消']
    },function(index){
        console.log(index)
    })
}
showOpenDialog.onclick = function () {
    remote.dialog.showOpenDialog({
        // 開啟資料夾
        properties: ['openDirectory', 'openFile']

        // 開啟檔案
        // properties: ['openFile']
    }, function (data) {
        console.log(data)
    })
}
saveDialog.onclick = function () {
    remote.dialog.showSaveDialog({
        title: 'Save File',
        defaultPath: '/Users/poetry/Downloads/',
        // filters 指定一個檔案型別陣列,用於規定使用者可見或可選的特定型別範圍
        filters: [
            { name: 'Images', extensions: ['jpg', 'png', 'gif'] },
            { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
            { name: 'Custom File Type', extensions: ['as'] },
            { name: 'All Files', extensions: ['*'] }
        ]
    }, function (path) {
        // 不是真的儲存 ,具體還需nodejs處理
        console.log(path)
    })
}
複製程式碼

showError

remote.dialog.showErrorBox('警告', '操作有誤')
複製程式碼

image.png

showMessageBox

remote.dialog.showMessageBox({
    type: 'info',
    title: '提示資訊',
    message: '內容',
    buttons: ['確定', '取消']
},function(index){
    console.log(index)
})
複製程式碼

image.png

showOpenDialog

remote.dialog.showOpenDialog({
    // 開啟資料夾
    properties: ['openDirectory', 'openFile']

    // 開啟檔案
    // properties: ['openFile']
}, function (data) {
    console.log(data)
})
複製程式碼

image.png

showSaveDialog

remote.dialog.showSaveDialog({
    title: 'Save File',
    defaultPath: '/Users/poetry/Downloads/',
    // filters 指定一個檔案型別陣列,用於規定使用者可見或可選的特定型別範圍
    filters: [
        { name: 'Images', extensions: ['jpg', 'png', 'gif'] },
        { name: 'Movies', extensions: ['mkv', 'avi', 'mp4'] },
        { name: 'Custom File Type', extensions: ['as'] },
        { name: 'All Files', extensions: ['*'] }
    ]
}, function (path) {
    // 不是真的儲存 ,具體還需nodejs處理
    console.log(path)
})
複製程式碼

image.png

九、實現一個類似EditPlus的簡易記事本程式碼編輯器

程式碼 github.com/poetries/el…

十、系統托盤、托盤右鍵選單、托盤圖示閃爍

image.png

文件 electronjs.org/docs/api/tr…

系統托盤,托盤右鍵選單、托盤圖示閃爍 點選右上角關閉按鈕隱藏到托盤(仿防毒軟體)

1. 引入檔案

// src/index.js
const createWindow = () => {
    require('./main/tray.js')
};
複製程式碼

2. Electron 建立工作列圖示以及工作列圖示右鍵選單

// src/main/tray.js
var {
    Menu, Tray, app, BrowserWindow
} = require('electron');

const path = require('path');

var appIcon = new Tray(path.join(__dirname, '../static/lover.png'));

const menu = Menu.buildFromTemplate([
    {
        label: '設定',
        click: function() {} //開啟相應頁面 
    },
    {
        label: '幫助',
        click: function() {}
    },
    {
        label: '關於',
        click: function() {}
    },
    {
        label: '退出',
        click: function() { 
            // BrowserWindow.getFocusedWindow().webContents().send('close-main-window');
            app.quit();
    }
}])
// 滑鼠放上去提示資訊
appIcon.setToolTip('hello poetries');
appIcon.setContextMenu(menu);
複製程式碼

mac系統托盤

3. 監聽工作列圖示的單擊、雙擊事件

// 實現點選關閉按鈕,讓應用儲存在托盤裡面,雙擊托盤開啟
let win = BrowserWindow.getFocusedWindow()

win.on('close', (e)=>{
    e.preventDefault()
    win.hide()
})

iconTray.on('double-click', (e)=>{
    win.show()
})
複製程式碼

4. Electron 點選右上角關閉按鈕隱藏工作列圖示

const win = BrowserWindow.getFocusedWindow();

win.on('close', (e) =>{

    console.log(win.isFocused());
    
    if (!win.isFocused()) {
        win = null;
    } else {
        e.preventDefault();/*阻止應用退出*/
        win.hide();/*隱藏當前視窗*/
    }
})
複製程式碼

5. Electron 實現工作列閃爍圖示

var appIcon = new Tray(path.join(__dirname, '../static/lover.png'));

timer = setInterval(function() {
    count++;
    if (count % 2 == 0) {
        appIcon.setImage(path.join(__dirname, '../static/empty.ico'))
    } else {
        appIcon.setImage(path.join(__dirname, '../static/lover.png'))
    }
},
500);
複製程式碼

十一、訊息通知、監聽網路變 化、網路變化彈出通知框

11.1 訊息通知

1. Electron 實現訊息通知

Electron 裡面的訊息通知是基於 h5 的通知 api 實現的

文件 developer.mozilla.org/zh-CN/docs/…

1. 新建notification.js

// h5api實現通知
const path = require('path')

let options = {
    title: 'electron 通知API',
    body: 'hello poetries',
    icon: path.join('../static/img/favicon2.ico') // 通知圖示
}


document.querySelector('#showNotification').onclick = function () {
    let myNotification  = new window.Notification(options.title, options)
    
    // 訊息可點選
    myNotification.onclick = function () {
        console.log('click notification')
    }
}
複製程式碼

2. 引入

<!--src/index.html-->

<button id="showNotification">彈出訊息通知</button>
<script src="render/notification.js"></script>
複製程式碼

mac上的訊息通知

mac上的訊息通知

11.2 監聽網路變化

1. 基本使用

 // 監聽網路變化
// 端開網路 再次連線測試
 window.addEventListener('online', function(){
    console.log('online')
 }); 
 
 window.addEventListener('offline', function(){
    console.log('offline')
 });
複製程式碼

2. 監聽網路變化實現訊息通知

// 端開網路 再次連線測試
// 監聽網路變化實現訊息通知
window.addEventListener('online', function(){
   console.log('online')
}); 
window.addEventListener('offline', function(){
   // 斷開網路觸發事件
   var options = {
       title: 'QQ郵箱',
       body: '網路異常,請檢查你的網路',
       icon: path.join('../static/img/favicon2.ico') // 通知圖示
   }
   var myNotification  = new window.Notification(options.title, options)
   myNotification.onclick = function () {
       console.log('click notification')
   }
});
複製程式碼

image.png

十二、註冊全域性快捷鍵/剪下板事件/nativeImage 模組

Electron 註冊全域性快捷鍵 (globalShortcut) 以及 clipboard 剪 切板事件以及 nativeImage 模組(實現類似播放器點選機器碼自動複製功 能)

12.1 註冊全域性快捷鍵

image.png

1. 新建src/main/shortCut.js

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

app.on('ready', ()=>{
    // 註冊全域性快捷鍵
    globalShortcut.register('command+e', ()=>{
        console.log(1)
    })

    // 檢測快捷鍵是否註冊成功 true是註冊成功
    let isRegister = globalShortcut.isRegistered('command+e')
    console.log(isRegister)
})

// 退出的時候取消全域性快捷鍵
app.on('will-quit', ()=>{
    globalShortcut.unregister('command+e')
})
複製程式碼

2. 引入src/index.js

// 注意在外部引入即可 不用放到app中
require('./main/shortCut.js')
複製程式碼

12.2 剪下板clipboard、nativeImage 模組

image.png

1. html

<!--src/index.html-->
<div>
  <h2>雙擊下面資訊複製</h2>
  <p id='msg'>123456789</p>
  <button id="plat">貼上</button><br />
  <input id="text" type="text"/>
</div>.
<div>
  <h2>複製圖片到介面</h2>
  <button id="copyImg">複製圖片</button><br />
</div>
<script src="render/clipboard.js"></script>
複製程式碼

2. 新建src/render/clipboard.js

// clipboard可以在主程式或渲染程式使用
const { clipboard, nativeImage }  = require('electron')

//複製
// 執行ctrl+v可看到複製的內容
// clipboard.writeText('poetries')

// clipboard.readText() //獲取複製的內容 貼上

// 雙擊複製訊息
let msg = document.querySelector('#msg')
let plat = document.querySelector('#plat')
let text = document.querySelector('#text')

msg.ondblclick  = function () {
    clipboard.writeText(msg.innerHTML)
    alert(msg.innerHTML)
}
plat.onclick = function () {
    text.value = clipboard.readText()
}

// 複製圖片顯示到介面
let copyImg = document.querySelector('#copyImg')
copyImg.onclick = function () {
    // 結合nativeImage模組
    let image = nativeImage.createFromPath('../static/img/lover.png') 

    // 複製圖片
    clipboard.writeImage(image)

    // 貼上圖片
    let imgSrc = clipboard.readImage().toDataURL() // base64圖片

    // 顯示到頁面上
    let imgDom = new Image()
    imgDom.src = imgSrc 
    document.body.appendChild(imgDom)
}
複製程式碼

十三、結合electron-vue

13.1 electron-vue 的使用

1. electron-vue 的一些資源

github.com/SimulatedGR…

Electron-vue 文件 simulatedgreg.gitbooks.io/electron-vu…

2. electron-vue 環境搭建、建立專案

npm install -g vue-cli

vue init simulatedgreg/electron-vue my-project

cd my-project

yarn # or npm install

yarn run dev # or npm run dev
複製程式碼

3. electron-vue 目錄結構分析

image.png

13.2 electron-vue 中使用 sass/ElementUi

1. electron-vue UI 框架 ElementUi 的使用

element-cn.eleme.io/#/zh-CN

2. electron-vue 中使用 sass

# 安裝 sass-loader:

npm install --save-dev sass-loader node-sass
複製程式碼
<!--vue 檔案中修改 style 為如下程式碼:-->

<style lang="scss"> 
    body {
        /* SCSS */ 
    }
</style>
複製程式碼

13.3 electron-vue 中隱藏頂部選單隱藏

electron-vue 中隱藏頂部選單隱藏頂部最大化、最小化、關閉按鈕 自定最大化、最小化 、關閉按鈕

1. electron-vue 中隱藏頂部選單

// src/main/index.js
mainWindow.setMenu(null)
複製程式碼

2. electron-vue 中隱藏關閉 最大化 最小化按鈕

// src/main/index.js
mainWindow = new BrowserWindow({
    height: 620,
    useContentSize: true,
    width: 1280,
    frame: false /*去掉頂部導航 去掉關閉按鈕 最大化最小化按鈕*/
})
複製程式碼

3 .electron-vue 自定義關閉/最大化最小化按鈕

// 注意在mac下不需要監聽視窗最大最小化、以為系統預設支援,這個只是針對windows平臺

ipc.on('window-min',function() {
    mainWindow.minimize();
})

//登入視窗最大化 
ipc.on('window-max',function(){
    if (mainWindow.isMaximized()) {
        mainWindow.restore();
    } else {
        mainWindow.maximize();
    }
}) 

ipc.on('window-close',function() {
    mainWindow.close();
})
複製程式碼

4. electron-vue 自定義導航可拖拽

  • 可拖拽的 css: -webkit-app-region: drag;
  • 不可拖拽的 css: -webkit-app-region: no-drag;

13.4 使用electron-vue開發輿情監控系統

專案原始碼,僅做入門學習參考 github.com/poetries/yu…

13.4.1 配置開發環境

1. 專案搭建

npm install -g vue-cli

vue init simulatedgreg/electron-vue my-project

cd my-project

yarn # or npm install

yarn run dev # or npm run dev
複製程式碼

2. 安裝一些依賴

# 安裝 sass-loader:
npm install --save-dev sass-loader node-sass

# 安裝elementUI、js-md5
npm i element-ui  js-md5 -S
複製程式碼
  • .electron-vue/webpack.renderer.config.js中配置sass-loader就可以編寫``sass`了
<!--vue 檔案中修改 style 為如下程式碼:-->

<style lang="scss"> 
    body {
        /* SCSS */ 
    }
</style>
複製程式碼

13.4.2 主程式配置

1. src/main/index.js

function createWindow () {
  // 去掉頂部選單
  mainWindow.setMenu(null)
  
  // 選單項
  require('./model/menu.js');
  
  // 系統托盤相關
  require('./model/tray.js');
複製程式碼

2. src/main/menu.js選單配置

const { Menu,ipcMain,BrowserWindow} = require('electron');


//右鍵選單
const contextMenuTemplate=[
    {
        label: '複製', role: 'copy' },
    {
        label: '黏貼', role: 'paste' },        
    { type: 'separator' }, //分隔線
    {
        label: '其他功能',     
        click: () => {
        console.log('click')
         }
    }
];

const contextMenu=Menu.buildFromTemplate(contextMenuTemplate);


ipcMain.on('contextmenu',function(){

    contextMenu.popup(BrowserWindow.getFocusedWindow());

})
複製程式碼

3. src/main/tray.js系統托盤配置

托盤點選監聽事件只有在windows下才生效,mac系統預設支援

(function () {
    const path=require('path');
    const {app,Menu,BrowserWindow,Tray, shell} = require('electron');

    //建立系統托盤
    const tray = new Tray(path.resolve(__static, 'favicon.png'))

    //給托盤增加右鍵選單
    const template= [
        {
            label: '設定',
            click: function () {
                shell.openExternal('http://blog.poetries.top')
            }
        },
        {
            label: '幫助',
            click: function () {
                shell.openExternal('http://blog.poetries.top/2019/01/06/electron-summary')
            }
        },
        {
            label: '關於',
            click: function () {
                shell.openExternal('https://github.com/poetries/yuqing-monitor-electron')
            }
        },
        {
            label: '退出',
            click: function () {
                // BrowserWindow.getFocusedWindow().webContents().send('close-main-window');
                app.quit();
            
            }
        }
    ];

    const menu = Menu.buildFromTemplate(template);
    tray.setContextMenu(menu);


    tray.setToolTip('輿情監控系統');


    //監聽關閉事件隱藏到系統托盤
    // 這裡需要注意:在window中才生效,mac下系統預設支援
    // var win = BrowserWindow.getFocusedWindow();
    // win.on('close',(e)=>{
    //         if(!win.isFocused()){
    //             win=null;
    //         }else{
    //             e.preventDefault();  /*阻止應用退出*/

    //             win.hide(); /*隱藏當前視窗*/

    //         }       
    // })

    // //監聽托盤的雙擊事件
    // tray.on('double-click',()=>{               
    //     win.show();
    // })
})()
複製程式碼

4. src/main/shortCut.js快捷鍵配置

src/main/index.js中引入(require('src/main/shortCut.js'))即可,不需要放到app監控中

var {globalShortcut, app} = require('electron')

app.on('ready', ()=>{
    // 註冊全域性快捷鍵
    globalShortcut.register('command+e', ()=>{
        console.log(1)
    })

    // 檢測快捷鍵是否註冊成功 true是註冊成功
    let isRegister = globalShortcut.isRegistered('command+e')
    console.log(isRegister)
})

// 退出的時候取消全域性快捷鍵
app.on('will-quit', ()=>{
    globalShortcut.unregister('command+e')
})
複製程式碼

13.4.3 渲染程式配置

1. src/render/main.js配置

import Vue from 'vue'
import axios from 'axios'

import App from './App'
import router from './router'
import store from './store'

import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import VueHighcharts from 'vue-highcharts';
import VueSocketIO from 'vue-socket.io'

Vue.use(ElementUI);
Vue.use(VueHighcharts);

//引入socket.io配置連線
Vue.use(new VueSocketIO({
  debug: true,
  connection: 'http://118.123.14.36:3000',
  vuex: {
      store,
      actionPrefix: 'SOCKET_',
      mutationPrefix: 'SOCKET_'
  }
}))

if (!process.env.IS_WEB) Vue.use(require('vue-electron'))
Vue.http = Vue.prototype.$http = axios
Vue.config.productionTip = false


/* eslint-disable no-new */
new Vue({
  components: { App },
  router,
  store,
  template: '<App/>'
}).$mount('#app')
複製程式碼

2. 路由配置src/renderer/router/index.js

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/home',
      name: 'home',
      component: require('@/components/Home').default
    },
    {
      path: '/report',
      name: 'report',
      component: require('@/components/Report').default
    },
    {
      path: '/negativereport',
      name: 'negativereport',
      component: require('@/components/NegativeReport').default
    },
    {
      path: '/positivereport',
      name: 'positivereport',
      component: require('@/components/PositiveReport').default
    },
    {
      path: '/keyword',
      name: 'keyword',
      component: require('@/components/KeyWord').default
    },
    {
      path: '/alarm',
      name: 'alarm',
      component: require('@/components/Alarm').default
    },
    {
      path: '/msg',
      name: 'msg',
      component: require('@/components/Msg').default
    },
    {
      path: '*',
      redirect: '/home'
    }
  ]
})
複製程式碼

其他頁面更多詳情Github

3. 在渲染程式中使用主程式方式

// electron掛載到了vue例項上 $electron
this.$electron.shell
複製程式碼

13.4.4 多平臺打包

需要注意的是打包mac版本在mac系統上打包,打包window則在windows上打包,可以避免很多問題

# 在不同平臺上執行即可打包應用
npm run build
複製程式碼

13.4.4.1 打包介紹

electron-vue打包文件

1. electron 中構建應用最常用的模組

  • electron-packager
  • electron-builder

electron-packagerelectron-builder在自己單獨建立的應用用也可以完成打包功 能。但是由於配置太複雜所以我們不建議單獨配置

2. electron-forge

github.com/electron-us…

electron-forge package 
electron-forge make
複製程式碼

3. electron-vue中的打包方式

# https://simulatedgreg.gitbooks.io/electron-vue/content/cn/using-electron-packager. html
# 之需要執行一條命令
npm run build
複製程式碼

13.4.4.2 修改應用資訊

1. 修改package.json

image.png

2. 修改src/index.ejs標題資訊

3. 修改build/icons圖示

13.4.4.3 打包遇到的問題

1. 建立應用托盤的時候可能會遇到錯誤

  • 把托盤圖片放在根目錄static裡面,然後注意下面寫法。
var tray = new Tray(path.join(__static,'favicon.ico'))
複製程式碼
  • 如果托盤路徑沒有問題,還是包托盤相關錯誤的話,把托盤對應的圖片換成.png 格式重試

2. 模組問題可能會遇到的錯誤

image.png

image.png

解決辦法

  • 刪掉 node_modules 然後重新用 npm install 安裝依賴
  • yarn 來安裝模組
  • 用手機建立一個熱點電腦連上熱點重試

最後執行yarn run build即可

專案打包結果

專案截圖

輿情監控系統頁面

登入頁

首頁

全部輿情

輿情關鍵詞

增加關鍵詞

輿情報警設定

系統系統托盤、electron 訊息通知 (類似騰訊新聞)

系統托盤

訊息通知

專案原始碼 github.com/poetries/yu…

十四、更多參考

相關文章