文章發(fā)表于 http://blog.poetries.top/2019/01/06/electron-summary
一掸茅、前言
-
NW.js
和Electron
都可以用前端的知識來開發(fā)桌面應(yīng)用。NW.js
和Electron
起初是同一 個(gè)作者開發(fā)匆光。后來種種原因分為兩個(gè)產(chǎn)品。一個(gè)命名為NW.js
(英特爾公司提供技術(shù)支持)酿联、 另一命名為Electron
(Github 公司提供技術(shù)支持)终息。 -
NW.js
和Electron
可以用Nodejs
中幾乎所有的模塊。NW.js
和Electron
不僅可以把html
寫的web
頁面打包成跨平臺可以安裝到電腦上面的軟件贞让,也可以通過javascript
訪問操作 系統(tǒng)原生的UI
和Api
(控制窗口周崭、添加菜單項(xiàng)目、托盤應(yīng)用菜單喳张、讀寫文件休傍、訪問剪貼板)。
github
的atom
編輯器蹲姐、微軟的vscode
編輯器磨取,包括阿里內(nèi)部的一些 軟件也是用electron
開發(fā)的
1. Electron 是由誰開發(fā)的?
Electron
是由Github
開發(fā)
2. Electron 是什么?
Electron
是一個(gè)用HTML
,CSS
和JavaScript
來構(gòu)建跨平臺桌面應(yīng)用程序的一個(gè)開源庫
3. Electron 把 HTML柴墩,CSS 和 JavaScript 組合的程序構(gòu)建為跨平臺桌面應(yīng)用程序的原理 是什么?
原理為
Electron
通過將Chromium
和Node.js
合并到同一個(gè)運(yùn)行時(shí)環(huán)境中忙厌,并將其打包為Mac
,Windows
和Linux
系統(tǒng)下的應(yīng)用來實(shí)現(xiàn)這一目的江咳。
4. Electron 何時(shí)出現(xiàn)的逢净,為什么會出現(xiàn)?
Electron
于2013
年作為構(gòu)建Atom
的框架而被開發(fā)出來。這兩個(gè)項(xiàng)目在2014
春季開源歼指。 (Atom:為 Github 上可編程的文本編輯器)
一些歷史:
-
2013
年4
月Atom Shell
項(xiàng)目啟動 爹土。 -
2014
年5
月Atom Shell
被開源 。 -
2015
年4
月Atom Shell
被重命名為Electron
-
2016
年5
月Electron
發(fā)布了v1.0.0
版本
5. Electron 當(dāng)前流行程度?
目前
Electron
已成為開源開發(fā)者踩身、初創(chuàng)企業(yè)和老牌公司常用的開發(fā)工具胀茵。
6. Electron 當(dāng)前由那些人在維護(hù)支持?
Electron
當(dāng)前由Github
上的一支團(tuán)隊(duì)和一群活躍的貢獻(xiàn)者維護(hù)。有些貢獻(xiàn)者是獨(dú)立開發(fā)者挟阻,有些則在用Electron
構(gòu)建應(yīng)用的大型公司里工作琼娘。
7. Electron 新版本多久發(fā)布一次?
Electron
的版本發(fā)布相當(dāng)頻繁峭弟。每當(dāng)Chromium
、Node.js
有重要的bug
修復(fù)脱拼,新API
或是版本更新時(shí)Electron
會發(fā)布新版本瞒瘸。
- 一般
Chromium
發(fā)行新的穩(wěn)定版后的一到兩周之內(nèi),Electron
中Chromium
的版本會對其進(jìn)行更新熄浓,具體時(shí)間根據(jù)升級所需的工作量而定情臭。
一般Node.js
發(fā)行新的穩(wěn)定版一個(gè)月后,Electron
中Node.js
的版本會對其進(jìn)行更新赌蔑,具 體時(shí)間根據(jù)升級所需的工作量而定俯在。
8. Electron 的核心理念是什么?
Electron
的核心理念是:保持Electron
的體積小和可持續(xù)性開發(fā)。
如:為了保持Electron
的小巧 (文件體積) 和可持續(xù)性開發(fā) (以防依賴庫和API
的泛濫) 惯雳,Electron
限制了所使用的核心項(xiàng)目的數(shù)量朝巫。
比如Electron
只用了Chromium
的渲染庫而不是其全部組件。這使得升級Chromium
更加容易石景,但也意味著Electron
缺少了Google Chrome
里的一些瀏覽器相關(guān)的特性劈猿。 添加到Electron
的新功能應(yīng)該主要是原生API
。 如果可以的話潮孽,一個(gè)功能應(yīng)該盡可能的成 為一個(gè)Node.js
模塊揪荣。
9. Electron 當(dāng)前的最新版本為多少?
Electron
當(dāng)前的最新版本為4.0.1
(當(dāng)前時(shí)間為2019
年1
月6
號)
二、環(huán)境搭建
1. 安裝 electron
npm install -g electron
2. 克隆一個(gè)倉庫往史、快速啟動一個(gè)項(xiàng)目
# 克隆示例項(xiàng)目的倉庫
git clone https://github.com/electron/electron-quick-start
# 進(jìn)入這個(gè)倉庫
cd electron-quick-start
# 安裝依賴并運(yùn)行
npm install && npm start
3. 手動搭建一個(gè) electron 項(xiàng)目
- 新建一個(gè)項(xiàng)目目錄 例如:
electrondemo01
- 在
electrondemo01
目錄下面新建三個(gè)文件:index.html
仗颈、main.js
、package.json
-
index.html
里面用css
進(jìn)行布局(以前怎么寫現(xiàn)在還是怎么寫) - 在
main.js
中寫如下代碼
var electron =require('electron'); //electron 對象的引用
const app=electron.app; //BrowserWindow 類的引用
const BrowserWindow=electron.BrowserWindow;
let mainWindow=null; //監(jiān)聽?wèi)?yīng)用準(zhǔn)備完成的事件 app.on('ready',function(){
//監(jiān)聽?wèi)?yīng)用準(zhǔn)備完成的事件
app.on('ready',function(){
//創(chuàng)建窗口
mainWindow=new BrowserWindow({width: 800, height: 600}); mainWindow.loadFile('index.html');
mainWindow.on('closed', function () {
mainWindow = null; })
})
})
//監(jiān)聽所有窗口關(guān)閉的事件
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();
}
})
- 運(yùn)行
electron . #注意:命令后面有個(gè)點(diǎn)
4. electron-forge 搭建一個(gè) electron 項(xiàng)目
electron-forge
相當(dāng)于electron
的一個(gè)腳手架椎例,可以讓我們更方便的創(chuàng)建挨决、運(yùn)行、打包electron
項(xiàng)目
npm install -g electron-forge
electron-forge init my-new-app
cd my-new-app
npm start
三订歪、Electron 運(yùn)行流程
3.1 Electron 運(yùn)行的流程
3.2 Electron 主進(jìn)程和渲染進(jìn)程
-
Electron
運(yùn)行package.json
的main
腳本的進(jìn)程被稱為主進(jìn)程脖祈。 - 在主進(jìn)程中運(yùn)行的腳本通過創(chuàng)建
web
頁面來展示用戶界面。 一個(gè)Electron
應(yīng)用總是有且只有一個(gè)主進(jìn)程刷晋。 - 由于
Electron
使用了Chromium
(谷歌瀏覽器)來展示web
頁面盖高,所以Chromium
的 多進(jìn)程架構(gòu)也被使用到。 每個(gè)Electron
中的web
頁面運(yùn)行在它自己的渲染進(jìn)程中眼虱。 - 主進(jìn)程使用
BrowserWindow
實(shí)例創(chuàng)建頁面喻奥。每個(gè)BrowserWindow
實(shí)例都在自己的渲 染進(jìn)程里運(yùn)行頁面。 當(dāng)一個(gè)BrowserWindow
實(shí)例被銷毀后捏悬,相應(yīng)的渲染進(jìn)程也會被終止
- 進(jìn)程:進(jìn)程是計(jì)算機(jī)中的程序關(guān)于某數(shù)據(jù)集合上的一次運(yùn)行活動撞蚕,是 系統(tǒng)進(jìn)行資源分配和調(diào)度的基本單位,是操作系統(tǒng)結(jié)構(gòu)的基礎(chǔ)邮破。
- 線程:在一個(gè)程序里的一個(gè)執(zhí)行路線就叫做線程(
thread
)诈豌。更準(zhǔn)確的定義是: 線程是“一個(gè)進(jìn)程內(nèi)部的控制序列”仆救。 - 線程和進(jìn)程:一個(gè)程序至少有一個(gè)進(jìn)程,一個(gè)進(jìn)程至少有一個(gè)線程
3.3 Electron 渲染進(jìn)程中通過 Nodejs 讀取本地文件
在普通的瀏覽器中抒和,
web
頁面通常在一個(gè)沙盒環(huán)境中運(yùn)行矫渔,不被允許去接觸原生的資源。 然而Electron
的用戶在Node.js
的API
支持下可以在頁面中和操作系統(tǒng)進(jìn)行一些底層交 互摧莽。
Nodejs
在主進(jìn)程和渲染進(jìn)程中都可以使用庙洼。渲染進(jìn)程因?yàn)榘踩拗疲荒苤苯硬僮魃?GUI
镊辕。雖然如此油够,因?yàn)榧闪?Nodejs,渲染進(jìn)程也有了操作系統(tǒng)底層API
的能力征懈,Nodejs
中常用的Path
石咬、fs
、Crypto
等模塊在Electron
可以直接使用卖哎,方便我們處理鏈接鬼悠、路徑、 文件MD5
等亏娜,同時(shí)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 開啟調(diào)試模式
mainWindow.webContents.openDevTools();
四、Electron 模塊介紹
Electron
模塊介紹维贺、remote
模塊它掂、通 過BrowserWindow
打開新窗口
4.1 Electron 主進(jìn)程和渲染進(jìn)程中的模塊
4.2 Electron remote 模塊
remote
模塊提供了一種在渲染進(jìn)程(網(wǎng)頁)和主進(jìn)程之間進(jìn)行進(jìn)程間通訊(IPC
)的簡便途徑
Electron
中, 與GUI
相關(guān)的模塊(如dialog
,menu
等)只存在于主進(jìn)程,而不在渲染進(jìn)程中 溯泣。為了能從渲染進(jìn)程中使用它們虐秋,需要用ipc
模塊來給主進(jìn)程發(fā)送進(jìn)程間消息。使用remote
模塊垃沦,可以調(diào)用主進(jìn)程對象的方法客给,而無需顯式地發(fā)送進(jìn)程間消息,這類似于Java
的RMI
4.3 通過BrowserWindow 打開新窗口
Electron
渲染進(jìn)程中通過remote
模塊調(diào)用主進(jìn)程中的BrowserWindow
打開新窗口
// 主進(jìn)程代碼
const electron = require('electron');
// 控制應(yīng)用生命周期的模塊
const {app} = electron;
// 創(chuàng)建本地瀏覽器窗口的模塊
const {BrowserWindow} = electron;
// 指向窗口對象的一個(gè)全局引用栏尚,如果沒有這個(gè)引用起愈,那么當(dāng)該 javascript 對象被垃圾回收 的
// 時(shí)候該窗口將會自動關(guān)閉
let win;
function createWindow() {
// 創(chuàng)建一個(gè)新的瀏覽器窗口
win = new BrowserWindow({width: 1104, height: 620});//570+50
// 并且裝載應(yīng)用的 index.html 頁面
win.loadURL(`file://${__dirname}/html/index.html`);
// 打開開發(fā)工具頁面
win.webContents.openDevTools();
//當(dāng)窗口關(guān)閉時(shí)調(diào)用的方法
win.on('closed', () => {
// 解除窗口對象的引用,通常而言如果應(yīng)用支持多個(gè)窗口的話译仗,你會在一個(gè)數(shù)組里 // 存放窗口對象抬虽,在窗口關(guān)閉的時(shí)候應(yīng)當(dāng)刪除相應(yīng)的元素。
win = null;
});
}
// 當(dāng) Electron 完成初始化并且已經(jīng)創(chuàng)建了瀏覽器窗口纵菌,則該方法將會被調(diào)用阐污。
// 有些 API 只能在該事件發(fā)生后才能被使用
app.on('ready', createWindow);
// 當(dāng)所有的窗口被關(guān)閉后退出應(yīng)用
app.on('window-all-closed', () => {
// 對于 OS X 系統(tǒng),應(yīng)用和相應(yīng)的菜單欄會一直激活直到用戶通過 Cmd + Q 顯式退出
if (process.platform !== 'darwin') {
app.quit();
}
});
app.on('activate', () => {
// 對于 OS X 系統(tǒng)咱圆,當(dāng) dock 圖標(biāo)被點(diǎn)擊后會重新創(chuàng)建一個(gè) app 窗口笛辟,并且不會有其他
// 窗口打開
if (win === null) {
createWindow();
}
});
// 在這個(gè)文件后面你可以直接包含你應(yīng)用特定的由主進(jìn)程運(yùn)行的代碼功氨。
// 也可以把這些代碼放在另一個(gè)文件中然后在這里導(dǎo)入
// 渲染進(jìn)程代碼 /src/render/index.js
// 打開新窗口屬性用法有點(diǎn)類似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隱藏關(guān)閉按鈕、菜單選項(xiàng) true顯示
fullscreen:true, // 全屏展示
transparent: true
})
win.loadURL(path.join('file:',__dirname,'news.html'));
win.on('close',()=>{win = null});
}
五手幢、自定義頂部菜單/右鍵菜單
5.1 主進(jìn)程中調(diào)用Menu模塊-自定義軟件頂部菜單
Electron
中Menu
模塊可以用來創(chuàng)建原生菜單捷凄,它可用作應(yīng)用菜單和context
菜單
這個(gè)模塊是一個(gè)主進(jìn)程的模塊,并且可以通過
remote
模塊給渲染進(jìn)程調(diào)用
// main/menu.js
const { Menu } = require('electron')
// 文檔 https://electronjs.org/docs/api/menu-item
// 菜單項(xiàng)目
let menus = [
{
label: '文件',
submenu: [
{
label: '新建文件',
accelerator: 'ctrl+n', // 綁定快捷鍵
click: function () { // 綁定事件
console.log('新建文件')
}
},
{
label: '新建窗口',
click: function () {
console.log('新建窗口')
}
}
]
},
{
label: '編輯',
submenu: [
{
label: '復(fù)制',
role: 'copy' // 調(diào)用內(nèi)置角色實(shí)現(xiàn)對應(yīng)功能
},
{
label: '剪切',
role: 'cut' // 調(diào)用內(nèi)置角色實(shí)現(xiàn)對應(yīng)功能
}
]
},
{
label: '視圖',
submenu: [
{
label: '瀏覽'
},
{
label: '搜索'
}
]
}
]
let m = Menu.buildFromTemplate(menus)
Menu.setApplicationMenu(m)
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/menu.js')
};
我們給菜單綁定事件,在命令行控制臺可以看到
5.2 渲染進(jìn)程中調(diào)用Menu模塊
不推薦使用這種方式,建議在主進(jìn)程中使用
1. remote
通過
remote
調(diào)用主進(jìn)程的方法
// 菜單引入的方式發(fā)生變化
const { Menu } = require('electron').remote
// 其他代碼和上面菜單一樣
// ...
2. 加入index.html
<script src="render/menu.js"></script>
5.3 渲染進(jìn)程中自定義右鍵菜單
1. 定義菜單
// render/menu.js
// 在渲染進(jìn)程中通過remote模塊調(diào)用主進(jìn)程中的模塊
const { Menu } = require('electron').remote
const { remote } = require('electron')
// 文檔 https://electronjs.org/docs/api/menu-item
// 菜單項(xiàng)目
let menus = [
{
label: '文件',
submenu: [
{
label: '新建文件',
accelerator: 'ctrl+n', // 綁定快捷鍵
click: function () { // 綁定事件
console.log('新建文件')
}
},
{
label: '新建窗口',
click: function () {
console.log('新建窗口')
}
}
]
},
{
label: '編輯',
submenu: [
{
label: '復(fù)制',
role: 'copy' // 調(diào)用內(nèi)置角色實(shí)現(xiàn)對應(yīng)功能
},
{
label: '剪切',
role: 'cut' // 調(diào)用內(nèi)置角色實(shí)現(xiàn)對應(yīng)功能
}
]
},
{
label: '視圖',
submenu: [
{
label: '瀏覽'
},
{
label: '搜索'
}
]
}
]
let m = Menu.buildFromTemplate(menus)
// Menu.setApplicationMenu(m)
// 綁定右鍵菜單
window.addEventListener('contextmenu', (e)=>{
e.preventDefault()
m.popup({
window: remote.getCurrentWindow()
})
}, false)
2. 引入
<!--index.html-->
<script src="render/menu.js"></script>
六屈藐、進(jìn)程通信
- 渲染進(jìn)程 https://electronjs.org/docs/api/ipc-renderer
- 主進(jìn)程 https://electronjs.org/docs/api/ipc-main
6.1 主進(jìn)程與渲染進(jìn)程之間的通信
有時(shí)候我們想在渲染進(jìn)程中通過一個(gè)事件去執(zhí)行主進(jìn)程里面的方法及皂。或者在渲染進(jìn)程中通知 主進(jìn)程處理事件,主進(jìn)程處理完成后廣播一個(gè)事件讓渲染進(jìn)程去處理一些事情。這個(gè)時(shí)候就 用到了主進(jìn)程和渲染進(jìn)程之間的相互通信
Electron
主進(jìn)程,和渲染進(jìn)程的通信主要用到兩個(gè)模塊:ipcMain
和ipcRenderer
-
ipcMain
:當(dāng)在主進(jìn)程中使用時(shí)院刁,它處理從渲染器進(jìn)程(網(wǎng)頁)發(fā)送出來的異步和同步信息,當(dāng)然也有可能從主進(jìn)程向渲染進(jìn)程發(fā)送消息。 -
ipcRenderer
: 使用它提供的一些方法從渲染進(jìn)程 (web
頁面) 發(fā)送同步或異步的消息到主進(jìn)程粪狼。 也可以接收主進(jìn)程回復(fù)的消息
6.1.1 渲染進(jìn)程給主進(jìn)程發(fā)送異步消息
間接實(shí)現(xiàn)渲染進(jìn)程執(zhí)行主進(jìn)程里面的方法
1. 引入ipcRender
<!--src/index.html-->
<button id="send">在 渲染進(jìn)程中執(zhí)行主進(jìn)程里的方法(異步)</button>
<script src="render/ipcRender.js"></script>
2. 引入ipcMain
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain.js')
};
3. 渲染進(jìn)程發(fā)送消息
// src/render/ipcRender.js
//渲染進(jìn)程
let send = document.querySelector('#send');
const { ipcRenderer } = require('electron');
send.onclick = function () {
// 傳遞消息給主進(jìn)程
// 異步
ipcRenderer.send('sendMsg', {name:'poetries', age: 23})
}
2. 主進(jìn)程接收消息
// src/main/ipcMain.js
//主進(jìn)程
const { ipcMain } = require('electron')
// 主進(jìn)程處理渲染進(jìn)程廣播數(shù)據(jù)
ipcMain.on('sendMsg', (event, data)=> {
console.log('data\n ', data)
console.log('event\n ', event)
})
6.1.2 渲染進(jìn)程發(fā)送消息退腥,主進(jìn)程接收消息并反饋
渲染進(jìn)程給主進(jìn)程發(fā)送異步消息,主進(jìn)程接收到異步消息以后通知渲染進(jìn)程
1. 引入ipcRender
<!--src/index.html-->
<button id="sendFeedback">在 渲染進(jìn)程中執(zhí)行主進(jìn)程里的方法鸳玩,并反饋給主進(jìn)程(異步)</button>
<script src="render/ipcRender.js"></script>
2. 引入ipcMain
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain.js')
};
3. 渲染進(jìn)程發(fā)送消息
// src/render/ipcRender.js
//渲染進(jìn)程
let sendFeedback = document.querySelector('#sendFeedback');
const { ipcRenderer } = require('electron');
// 向主進(jìn)程發(fā)送消息
sendFeedback.onclick = function () {
// 觸發(fā)主進(jìn)程里面的方法
ipcRenderer.send('sendFeedback', {name:'poetries', age: 23})
}
4. 主進(jìn)程收到消息處理并廣播反饋通知渲染進(jìn)程
// src/main/ipcMain.js
//主進(jìn)程
const { ipcMain } = require('electron')
// 主進(jìn)程處理渲染進(jìn)程廣播數(shù)據(jù)阅虫,并反饋給渲染進(jìn)程
ipcMain.on('sendFeedback', (event, data)=> {
// console.log('data\n ', data)
// console.log('event\n ', event)
// 主進(jìn)程給渲染進(jìn)程廣播數(shù)據(jù)
event.sender.send('sendFeedbackToRender', '來自主進(jìn)程的反饋')
})
5. 渲染進(jìn)程處理主進(jìn)程廣播的數(shù)據(jù)
// src/render/ipcRender.js
// 向主進(jìn)程發(fā)送消息后,接收主進(jìn)程廣播的事件
ipcRenderer.on('sendFeedbackToRender', (e, data)=>{
console.log('event\n ', e)
console.log('data\n ', data)
})
6.1.3 渲染進(jìn)程給主進(jìn)程發(fā)送同步消息
1. 引入ipcRender
<!--src/index.html-->
<button id="sendSync">渲染進(jìn)程和主進(jìn)程同步通信</button>
<script src="render/ipcRender.js"></script>
2. 引入ipcMain
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain.js')
};
3. 渲染進(jìn)程給主進(jìn)程同步通信
// src/render/ipcMain.js
let sendSync = document.querySelector('#sendSync');
// 渲染進(jìn)程和主進(jìn)程同步通信
sendSync.onclick = function () {
// 同步廣播數(shù)據(jù)
let msg = ipcRenderer.sendSync('sendsync', {name:'poetries', age: 23})
// 同步返回主進(jìn)程反饋的數(shù)據(jù)
console.log('msg\n ', msg)
}
4. 主進(jìn)程接收數(shù)據(jù)處理
// src/main/ipcMain.js
// 渲染進(jìn)程和主進(jìn)程同步通信 接收同步廣播
ipcMain.on('sendsync', (event, data)=> {
// console.log('data\n ', data)
// console.log('event\n ', event)
// 主進(jìn)程給渲染進(jìn)程廣播數(shù)據(jù)
event.returnValue ='渲染進(jìn)程和主進(jìn)程同步通信 接收同步廣播不跟,來自主進(jìn)程的反饋.';
})
6.1.4 渲染進(jìn)程廣播通知主進(jìn)程打開窗口
一般都是在渲染進(jìn)程中執(zhí)行廣播操作颓帝,去通知主進(jìn)程完成任務(wù)
1. 引入openWindow
<!--src/index.html-->
<button id="sendSync">渲染進(jìn)程和主進(jìn)程同步通信</button>
<script src="render/openWindow.js"></script>
2. 引入ipcMain2
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain2.js')
};
3. 渲染進(jìn)程通知主進(jìn)程打開窗口
// src/render/openWindow.js
/* eslint-disable */
let openWindow = document.querySelector('#openWindow');
var { ipcRenderer } = require('electron');
// 渲染進(jìn)程和渲染進(jìn)程直接的通信========
openWindow.onclick = function () {
// 通過廣播的形式 通知主進(jìn)程執(zhí)行操作
ipcRenderer.send('openwindow', {name:'poetries', age: 23})
}
4. 主進(jìn)程收到通知執(zhí)行操作
// src/main/ipcMain2.js
/* eslint-disable */
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')
let win;
// 接收到廣播
ipcMain.on('openwindow', (e, data)=> {
// 調(diào)用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 渲染進(jìn)程與渲染進(jìn)程之間的通信
也就是兩個(gè)窗口直接的通信
6.2.1 localstorage傳值
Electron
渲染進(jìn)程通過localstorage
給另一個(gè)渲染進(jìn)程傳值
1. 引入openWindow
<!--src/index.html-->
<button id="sendSync">渲染進(jìn)程和主進(jìn)程同步通信</button>
<script src="render/openWindow.js"></script>
2. 引入ipcMain2
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain2.js')
};
3. 渲染進(jìn)程通知主進(jìn)程打開窗口
// src/render/openWindow.js
/* eslint-disable */
let openWindow = document.querySelector('#openWindow');
var { ipcRenderer } = require('electron');
// 渲染進(jìn)程和渲染進(jìn)程直接的通信========
openWindow.onclick = function () {
// 通過廣播的形式 通知主進(jìn)程執(zhí)行操作
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. 主進(jìn)程收到通知執(zhí)行操作
// src/main/ipcMain2.js
/* eslint-disable */
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')
let win;
// 接收到廣播
ipcMain.on('openwindow', (e, data)=> {
// 調(diào)用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方式實(shí)現(xiàn)
通過
BrowserWindow
和webContents
模塊實(shí)現(xiàn)渲染進(jìn)程和渲染進(jìn)程的通信
webContents
是一個(gè)事件發(fā)出者.它負(fù)責(zé)渲染并控制網(wǎng)頁,也是BrowserWindow
對象的屬性
需要了解的幾個(gè)知識點(diǎn)
- 獲取當(dāng)前窗口的
id
const winId = BrowserWindow.getFocusedWindow().id;
- 監(jiān)聽當(dāng)前窗口加載完成的事件
win.webContents.on('did-finish-load',(event) => {
})
- 同一窗口之間廣播數(shù)據(jù)
win.webContents.on('did-finish-load',(event) => {
win.webContents.send('msg',winId,'我是 index.html 的數(shù)據(jù)');
})
- 通過
id
查找窗口
let win = BrowserWindow.fromId(winId);
下面是具體演示
1. 引入openWindow
<!--src/index.html-->
<button id="sendSync">渲染進(jìn)程和主進(jìn)程同步通信</button>
<script src="render/openWindow.js"></script>
2. 引入ipcMain2
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/ipcMain2.js')
};
3. 渲染進(jìn)程通知主進(jìn)程打開窗口
// src/render/openWindow.js
/* eslint-disable */
let openWindow = document.querySelector('#openWindow');
var { ipcRenderer } = require('electron');
// 渲染進(jìn)程和渲染進(jìn)程直接的通信========
openWindow.onclick = function () {
// 通過廣播的形式 通知主進(jìn)程執(zhí)行操作
ipcRenderer.send('openwindow', {name:'poetries', age: 23})
}
4. 主進(jìn)程收到通知執(zhí)行操作
// src/main/ipcMain2.js
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')
let win;
// 接收到廣播
ipcMain.on('openwindow', (e, userInfo)=> {
// 調(diào)用window打開新窗口
win = new BrowserWindow({
width: 400,
height: 300,
});
win.loadURL(path.join('file:',__dirname, '../news.html'));
// 新開窗口調(diào)試模式
win.webContents.openDevTools()
// 把渲染進(jìn)程傳遞過來的數(shù)據(jù)再次傳遞給渲染進(jìn)程news
// 等待窗口加載完
win.webContents.on('did-finish-load', ()=>[
win.webContents.send('toNews', userInfo)
])
win.on('closed', () => {
win = null;
});
})
5. news接收主進(jìn)程傳遞的數(shù)據(jù)
數(shù)據(jù)經(jīng)過渲染進(jìn)程->主進(jìn)程->
news
渲染進(jìn)程
<!--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)
// 監(jiān)聽主進(jìn)程傳遞過來的數(shù)據(jù)
ipcRenderer.on('toNews',(e, userInfo)=>{
console.log(userInfo)
})
那么窝革,這里有一個(gè)問題购城,
news
進(jìn)程接收到了廣播后如何給出反饋呢?
1. 在主進(jìn)程中獲取窗口ID傳遞
// src/main/ipcMain2.js
let { ipcMain,BrowserWindow } = require('electron')
const path = require('path')
let win;
// 接收到廣播
ipcMain.on('openwindow', (e, userInfo)=> {
// 獲取當(dāng)前窗口ID 放在第一行保險(xiǎn) 因?yàn)楹竺嬉泊蜷_了新窗口使得獲取的ID有問題
let winId = BrowserWindow.getFocusedWindow().id
// 調(diào)用window打開新窗口
win = new BrowserWindow({
width: 400,
height: 300,
});
win.loadURL(path.join('file:',__dirname, '../news.html'));
// 新開窗口調(diào)試模式
win.webContents.openDevTools()
// 把渲染進(jìn)程傳遞過來的數(shù)據(jù)再次傳遞給渲染進(jìn)程news
// 等待窗口加載完
win.webContents.on('did-finish-load', ()=>[
win.webContents.send('toNews', userInfo, winId)
])
win.on('closed', () => {
win = null;
});
})
2. 在news進(jìn)程中廣播數(shù)據(jù)
// src/render/news.js
var { ipcRenderer } = require('electron');
// 注意這里 在渲染進(jìn)程中需要從remote中獲取BrowserWindow
const BrowerWindow = require('electron').remote.BrowserWindow;
// let username = localStorage.getItem('username')
// console.log(username)
// 監(jiān)聽主進(jìn)程傳遞過來的數(shù)據(jù)
ipcRenderer.on('toNews',(e, userInfo, winId)=>{
// windID 第一個(gè)窗口ID
// 獲取對應(yīng)ID的窗口
let firstWin = BrowerWindow.fromId(winId)
firstWin.webContents.send('toIndex', '來自news進(jìn)程反饋的信息')
console.log(userInfo)
})
3. 在另一個(gè)渲染進(jìn)程中處理廣播
/* eslint-disable */
let openWindow = document.querySelector('#openWindow');
var { ipcRenderer } = require('electron');
// 渲染進(jìn)程和渲染進(jìn)程直接的通信========
openWindow.onclick = function () {
// 傳遞消息給主進(jìn)程
ipcRenderer.send('openwindow', {name:'poetries', age: 23})
// 傳遞給打開的窗口 渲染進(jìn)程和渲染進(jìn)程直接的通信
localStorage.setItem('username', 'poetries')
}
// 接收news渲染進(jìn)程傳遞回來的消息
ipcRenderer.on('toIndex', (e, data)=>{
console.log('===', data)
})
七虐译、Electron Shell 模塊
7.1 Shell 模塊使用
Electron Shell
模塊在用戶默認(rèn)瀏覽器 中打開URL
以及Electron DOM webview
標(biāo)簽瘪板。Shell
既屬于主進(jìn)程模塊又是渲染進(jìn)程模塊
shell
模塊提供了集成其他桌面客戶端的關(guān)聯(lián)功能
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>
標(biāo)簽
Webview
與iframe
有點(diǎn)相似,但是與iframe
不同,webview
和你的應(yīng)用運(yùn)行的是不同的進(jìn)程漆诽。它不擁有渲染進(jìn)程的權(quán)限侮攀,并且應(yīng)用和嵌入內(nèi)容之間的交互全部都是異步的。因?yàn)檫@能 保證應(yīng)用的安全性不受嵌入內(nèi)容的影響厢拭。
<!--src/index.html中引入-->
<webview id="webview" src="http://blog.poetries.top" style="position:fixed; width:100%; height:100%">
</webview>
7.3 shell
模塊<webview>
結(jié)合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');
// 當(dāng)前窗口渲染網(wǎng)頁
function openWebView(url) {
// 獲取當(dāng)前窗口Id
let win = BrowserWindow.getFocusedWindow()
// 廣播通知渲染進(jìn)程打開webview
win.webContents.send('openwebview', url)
}
// 在窗口外打開網(wǎng)頁
function openWeb(url) {
shell.openExternal(url)
}
let template = [
{
label: '幫助',
submenu: [
{
label: '關(guān)于我們',
click: function () {
openWeb('http://blog.poetries.top')
}
},
{
type: 'separator'
},
{
label: '聯(lián)系我們',
click: function () {
openWeb('https://github.com/poetries')
}
}
]
},
{
label: '加載網(wǎng)頁',
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('http://www.reibang.com/users/94077fcddfc0/timeline')
}
}
]
},
{
label: '視頻網(wǎng)站',
submenu: [
{
label: '優(yōu)酷',
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
// 在主進(jìn)程src/index.js中引入
const createWindow = () => {
// 創(chuàng)建菜單
// 引入菜單模塊
require('./main/menu.js')
};
八兰英、Electron dialog 彈出框
dialog
屬于主進(jìn)程中的模塊
dialog
模塊提供了api
來展示原生的系統(tǒng)對話框,例如打開文件框供鸠,alert
框畦贸, 所以web
應(yīng)用可以給用戶帶來跟系統(tǒng)應(yīng)用相同的體驗(yàn)
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: '內(nèi)容',
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 指定一個(gè)文件類型數(shù)組,用于規(guī)定用戶可見或可選的特定類型范圍
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('警告', '操作有誤')
showMessageBox
remote.dialog.showMessageBox({
type: 'info',
title: '提示信息',
message: '內(nèi)容',
buttons: ['確定', '取消']
},function(index){
console.log(index)
})
showOpenDialog
remote.dialog.showOpenDialog({
// 打開文件夾
properties: ['openDirectory', 'openFile']
// 打開文件
// properties: ['openFile']
}, function (data) {
console.log(data)
})
showSaveDialog
remote.dialog.showSaveDialog({
title: 'Save File',
defaultPath: '/Users/poetry/Downloads/',
// filters 指定一個(gè)文件類型數(shù)組薄坏,用于規(guī)定用戶可見或可選的特定類型范圍
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)
})
九、實(shí)現(xiàn)一個(gè)類似EditPlus的簡易記事本代碼編輯器
代碼 https://github.com/poetries/electron-demo/tree/master/notepad
十胶坠、系統(tǒng)托盤君账、托盤右鍵菜單、托盤圖標(biāo)閃爍
系統(tǒng)托盤涵但,托盤右鍵菜單杈绸、托盤圖標(biāo)閃爍 點(diǎn)擊右上角關(guān)閉按鈕隱藏到托盤(仿殺毒軟件)
1. 引入文件
// src/index.js
const createWindow = () => {
require('./main/tray.js')
};
2. Electron 創(chuàng)建任務(wù)欄圖標(biāo)以及任務(wù)欄圖標(biāo)右鍵菜單
// 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: '設(shè)置',
click: function() {} //打開相應(yīng)頁面
},
{
label: '幫助',
click: function() {}
},
{
label: '關(guān)于',
click: function() {}
},
{
label: '退出',
click: function() {
// BrowserWindow.getFocusedWindow().webContents().send('close-main-window');
app.quit();
}
}])
// 鼠標(biāo)放上去提示信息
appIcon.setToolTip('hello poetries');
appIcon.setContextMenu(menu);
3. 監(jiān)聽任務(wù)欄圖標(biāo)的單擊帖蔓、雙擊事件
// 實(shí)現(xiàn)點(diǎn)擊關(guān)閉按鈕矮瘟,讓應(yīng)用保存在托盤里面,雙擊托盤打開
let win = BrowserWindow.getFocusedWindow()
win.on('close', (e)=>{
e.preventDefault()
win.hide()
})
iconTray.on('double-click', (e)=>{
win.show()
})
4. Electron 點(diǎn)擊右上角關(guān)閉按鈕隱藏任務(wù)欄圖標(biāo)
const win = BrowserWindow.getFocusedWindow();
win.on('close', (e) =>{
console.log(win.isFocused());
if (!win.isFocused()) {
win = null;
} else {
e.preventDefault();/*阻止應(yīng)用退出*/
win.hide();/*隱藏當(dāng)前窗口*/
}
})
5. Electron 實(shí)現(xiàn)任務(wù)欄閃爍圖標(biāo)
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);
十一塑娇、消息通知澈侠、監(jiān)聽網(wǎng)絡(luò)變 化、網(wǎng)絡(luò)變化彈出通知框
11.1 消息通知
1. Electron 實(shí)現(xiàn)消息通知
Electron
里面的消息通知是基于h5
的通知api
實(shí)現(xiàn)的
文檔 https://developer.mozilla.org/zh-CN/docs/Web/API/notification
1. 新建notification.js
// h5api實(shí)現(xiàn)通知
const path = require('path')
let options = {
title: 'electron 通知API',
body: 'hello poetries',
icon: path.join('../static/img/favicon2.ico') // 通知圖標(biāo)
}
document.querySelector('#showNotification').onclick = function () {
let myNotification = new window.Notification(options.title, options)
// 消息可點(diǎn)擊
myNotification.onclick = function () {
console.log('click notification')
}
}
2. 引入
<!--src/index.html-->
<button id="showNotification">彈出消息通知</button>
<script src="render/notification.js"></script>
mac
上的消息通知
11.2 監(jiān)聽網(wǎng)絡(luò)變化
1. 基本使用
// 監(jiān)聽網(wǎng)絡(luò)變化
// 端開網(wǎng)絡(luò) 再次連接測試
window.addEventListener('online', function(){
console.log('online')
});
window.addEventListener('offline', function(){
console.log('offline')
});
2. 監(jiān)聽網(wǎng)絡(luò)變化實(shí)現(xiàn)消息通知
// 端開網(wǎng)絡(luò) 再次連接測試
// 監(jiān)聽網(wǎng)絡(luò)變化實(shí)現(xiàn)消息通知
window.addEventListener('online', function(){
console.log('online')
});
window.addEventListener('offline', function(){
// 斷開網(wǎng)絡(luò)觸發(fā)事件
var options = {
title: 'QQ郵箱',
body: '網(wǎng)絡(luò)異常埋酬,請檢查你的網(wǎng)絡(luò)',
icon: path.join('../static/img/favicon2.ico') // 通知圖標(biāo)
}
var myNotification = new window.Notification(options.title, options)
myNotification.onclick = function () {
console.log('click notification')
}
});
十二哨啃、注冊全局快捷鍵/剪切板事件/nativeImage 模塊
Electron
注冊全局快捷鍵 (globalShortcut
) 以及clipboard
剪 切板事件以及nativeImage
模塊(實(shí)現(xiàn)類似播放器點(diǎn)擊機(jī)器碼自動復(fù)制功 能)
12.1 注冊全局快捷鍵
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)
})
// 退出的時(shí)候取消全局快捷鍵
app.on('will-quit', ()=>{
globalShortcut.unregister('command+e')
})
2. 引入src/index.js
// 注意在外部引入即可 不用放到app中
require('./main/shortCut.js')
12.2 剪切板clipboard、nativeImage 模塊
1. html
<!--src/index.html-->
<div>
<h2>雙擊下面信息復(fù)制</h2>
<p id='msg'>123456789</p>
<button id="plat">粘貼</button><br />
<input id="text" type="text"/>
</div>.
<div>
<h2>復(fù)制圖片到界面</h2>
<button id="copyImg">復(fù)制圖片</button><br />
</div>
<script src="render/clipboard.js"></script>
2. 新建src/render/clipboard.js
// clipboard可以在主進(jìn)程或渲染進(jìn)程使用
const { clipboard, nativeImage } = require('electron')
//復(fù)制
// 運(yùn)行ctrl+v可看到復(fù)制的內(nèi)容
// clipboard.writeText('poetries')
// clipboard.readText() //獲取復(fù)制的內(nèi)容 粘貼
// 雙擊復(fù)制消息
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()
}
// 復(fù)制圖片顯示到界面
let copyImg = document.querySelector('#copyImg')
copyImg.onclick = function () {
// 結(jié)合nativeImage模塊
let image = nativeImage.createFromPath('../static/img/lover.png')
// 復(fù)制圖片
clipboard.writeImage(image)
// 粘貼圖片
let imgSrc = clipboard.readImage().toDataURL() // base64圖片
// 顯示到頁面上
let imgDom = new Image()
imgDom.src = imgSrc
document.body.appendChild(imgDom)
}
十三写妥、結(jié)合electron-vue
13.1 electron-vue 的使用
1. electron-vue 的一些資源
Electron-vue
文檔 https://simulatedgreg.gitbooks.io/electron-vue/content/cn
2. electron-vue 環(huán)境搭建拳球、創(chuàng)建項(xiàng)目
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 目錄結(jié)構(gòu)分析
13.2 electron-vue 中使用 sass/ElementUi
1. electron-vue UI 框架 ElementUi 的使用
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 中隱藏頂部菜單隱藏頂部最大化、最小化珍特、關(guān)閉按鈕 自定最大化祝峻、最小化 、關(guān)閉按鈕
1. electron-vue 中隱藏頂部菜單
// src/main/index.js
mainWindow.setMenu(null)
2. electron-vue 中隱藏關(guān)閉 最大化 最小化按鈕
// src/main/index.js
mainWindow = new BrowserWindow({
height: 620,
useContentSize: true,
width: 1280,
frame: false /*去掉頂部導(dǎo)航 去掉關(guān)閉按鈕 最大化最小化按鈕*/
})
3 .electron-vue 自定義關(guān)閉/最大化最小化按鈕
// 注意在mac下不需要監(jiān)聽窗口最大最小化扎筒、以為系統(tǒng)默認(rèn)支持莱找,這個(gè)只是針對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 自定義導(dǎo)航可拖拽
- 可拖拽的
css
:-webkit-app-region: drag;
- 不可拖拽的
css
:-webkit-app-region: no-drag;
13.4 使用electron-vue開發(fā)輿情監(jiān)控系統(tǒng)
13.4.1 配置開發(fā)環(huán)境
1. 項(xiàng)目搭建
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 主進(jìn)程配置
1. src/main/index.js
function createWindow () {
// 去掉頂部菜單
mainWindow.setMenu(null)
// 菜單項(xiàng)
require('./model/menu.js');
// 系統(tǒng)托盤相關(guān)
require('./model/tray.js');
2. src/main/menu.js
菜單配置
const { Menu,ipcMain,BrowserWindow} = require('electron');
//右鍵菜單
const contextMenuTemplate=[
{
label: '復(fù)制', 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
系統(tǒng)托盤配置
托盤點(diǎn)擊監(jiān)聽事件只有在
windows
下才生效嗜桌,mac
系統(tǒng)默認(rèn)支持
(function () {
const path=require('path');
const {app,Menu,BrowserWindow,Tray, shell} = require('electron');
//創(chuàng)建系統(tǒng)托盤
const tray = new Tray(path.resolve(__static, 'favicon.png'))
//給托盤增加右鍵菜單
const template= [
{
label: '設(shè)置',
click: function () {
shell.openExternal('http://blog.poetries.top')
}
},
{
label: '幫助',
click: function () {
shell.openExternal('http://blog.poetries.top/2019/01/06/electron-summary')
}
},
{
label: '關(guān)于',
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('輿情監(jiān)控系統(tǒng)');
//監(jiān)聽關(guān)閉事件隱藏到系統(tǒng)托盤
// 這里需要注意:在window中才生效奥溺,mac下系統(tǒng)默認(rèn)支持
// var win = BrowserWindow.getFocusedWindow();
// win.on('close',(e)=>{
// if(!win.isFocused()){
// win=null;
// }else{
// e.preventDefault(); /*阻止應(yīng)用退出*/
// win.hide(); /*隱藏當(dāng)前窗口*/
// }
// })
// //監(jiān)聽托盤的雙擊事件
// tray.on('double-click',()=>{
// win.show();
// })
})()
4. src/main/shortCut.js
快捷鍵配置
在src/main/index.js
中引入(require('src/main/shortCut.js')
)即可,不需要放到app
監(jiān)控中
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)
})
// 退出的時(shí)候取消全局快捷鍵
app.on('will-quit', ()=>{
globalShortcut.unregister('command+e')
})
13.4.3 渲染進(jìn)程配置
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'
}
]
})
3. 在渲染進(jìn)程中使用主進(jìn)程方式
// electron掛載到了vue實(shí)例上 $electron
this.$electron.shell
13.4.4 多平臺打包
需要注意的是打包
mac
版本在mac
系統(tǒng)上打包骨宠,打包window
則在windows
上打包浮定,可以避免很多問題
# 在不同平臺上執(zhí)行即可打包應(yīng)用
npm run build
13.4.4.1 打包介紹
1. electron 中構(gòu)建應(yīng)用最常用的模塊
electron-packager
electron-builder
electron-packager
和electron-builder
在自己單獨(dú)創(chuàng)建的應(yīng)用用也可以完成打包功 能。但是由于配置太復(fù)雜所以我們不建議單獨(dú)配置
2. electron-forge
electron-forge package
electron-forge make
3. electron-vue中的打包方式
# https://simulatedgreg.gitbooks.io/electron-vue/content/cn/using-electron-packager. html
# 之需要執(zhí)行一條命令
npm run build
13.4.4.2 修改應(yīng)用信息
1. 修改package.json
2. 修改src/index.ejs標(biāo)題信息
3. 修改build/icons圖標(biāo)
13.4.4.3 打包遇到的問題
1. 創(chuàng)建應(yīng)用托盤的時(shí)候可能會遇到錯誤
- 把托盤圖片放在根目錄
static
里面层亿,然后注意下面寫法桦卒。
var tray = new Tray(path.join(__static,'favicon.ico'))
- 如果托盤路徑?jīng)]有問題,還是包托盤相關(guān)錯誤的話棕所,把托盤對應(yīng)的圖片換成
.png
格式重試
2. 模塊問題可能會遇到的錯誤
解決辦法
- 刪掉
node_modules
然后重新用npm install
安裝依賴 - 用
yarn
來安裝模塊 - 用手機(jī)創(chuàng)建一個(gè)熱點(diǎn)電腦連上熱點(diǎn)重試
最后執(zhí)行
yarn run build
即可
項(xiàng)目截圖
輿情監(jiān)控系統(tǒng)頁面
系統(tǒng)系統(tǒng)托盤闸盔、
electron
消息通知 (類似騰訊新聞)
項(xiàng)目源碼 https://github.com/poetries/yuqing-monitor-electron