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 打開新窗口

https://electronjs.org/docs/api/browser-window

// 主進程代碼
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模塊-自定義軟件頂部菜單

https://electronjs.org/docs/api/menu-item

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 模塊使用

文檔 https://electronjs.org/docs/api/shell

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

文檔 https://electronjs.org/docs/api/dialog

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的簡易記事本代碼編輯器

代碼 https://github.com/poetries/electron-demo/tree/master/notepad

十、系統托盤、托盤右鍵菜單、托盤圖標閃爍

 
image.png

文檔 https://electronjs.org/docs/api/tray

系統托盤,托盤右鍵菜單、托盤圖標閃爍 點擊右上角關閉按鈕隱藏到托盤(仿殺毒軟件)

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 實現的

文檔 https://developer.mozilla.org/zh-CN/docs/Web/API/notification

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 的一些資源

https://github.com/SimulatedGREG/electron-vue

Electron-vue 文檔 https://simulatedgreg.gitbooks.io/electron-vue/content/cn

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 的使用

http://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開發輿情監控系統

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

https://github.com/electron-userland/electron-forge

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 消息通知 (類似騰訊新聞)

 
系統托盤
 
消息通知

項目源碼 https://github.com/poetries/yuqing-monitor-electron

十四、更多參考

 

作者:poetries
鏈接:https://www.jianshu.com/p/2244653515a7
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

喜歡這篇文章?歡迎打賞~~

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM