Electron快速上手
基础模板改造
git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
npm install && npm start
脚手架工具开发
https://github.com/electron-userland/electron-forge
npx create-electron-app electronApp
或者
yarn create electron-app electronApp
进程调度
Electron 中, 与 GUI 相关的模块(如 dialog, menu 等)只存在于主进程,而不在渲染进程中 。 为了能从渲染进程中使用它们,需要用 ipc模块来给主进程发送进程间消息。使用 remote 模 块,可以调用主进程对象的方法
mainWindow=new BrowserWindow({width:800,height:600,webPreferences: {
nodeIntegration: true,//开启渲染进程中使用nodejs
enableRemoteModule: true//
}});
mainWindow.loadFile(path.join(__dirname, "new_render.html"));
顶部菜单,右键菜单
https://www.electronjs.org/docs/api/menu-item
顶部菜单是在主进程中运行,所以需要在main.js调用。
右键菜单是在渲染进程中运行,所以需要在html文件中运行。
//顶部菜单 src/ipcMain/menu.js
const { Menu } = require("electron");
var topMenu=[
{
label:"文件",
submenu:[
{
label:"新建",
accelerator:"ctrl+n",
click:()=>{
console.log("Ctrl+N")
}
},
{
type:"separator"
},
{
label:"保存"
}
]
},
{
label:"编辑",
submenu:[
{
label:"复制",
role:"copy",
click:()=>{
console.log("copy")
}
}
]
}
];
var menuBuilder=Menu.buildFromTemplate(menuTemplate);
Menu.setApplicationMenu(menuBuilder);
//src/main.js
const createWindow = () => {
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences:{
nodeIntegration:true,
enableRemoteModule:true
}
});
//在渲染进程中开启调试模式
mainWindow.webContents.openDevTools()
mainWindow.loadFile(path.join(__dirname, "index.html"));
//自定义顶部菜单
require('./ipcMain/menu');
}
鼠标右键菜单内容同上,只不过需要在index.html渲染进程中引入,且需要通过remote调用主进程中的menu模块
//渲染进程
const { remote } = require("electron");
const Menu = remote.Menu;
....
window.onload = () => {
window.addEventListener("contextmenu", (e) => {
e.preventDefault();
//弹出右键差菜单
menuBuilder.popup({window:remote.getCurrentWindow()});
}, false)
}
主进程与渲染进程间通信
Electron 主进程和渲染进程的通信主要用到两个模块:ipcMain 和 ipcRenderer
ipcMain:当在主进程中使用时,它处理从渲染器进程(网页)发送出来的异步和同步信息, 当然也有可能从主进程向渲染进程发送消息。
ipcRenderer: 使用它提供的一些方法从渲染进程 (web 页面) 发送同步或异步的消息到主 进程。 也可以接收主进程回复的消息。
渲染进程给主进程发送异步消息:
const { ipcRenderer } = require('electron') ;
ipcRenderer.send('render2Main',{name:'steven'}); //渲染进程发送异步消息到主进程
ipcRenderer.on("main2render",(event,data)=>{
console.log("主进程响应给渲染进程的数据",data);
})
//主进程监听渲染进程传递过来的数据,并发送消息给渲染进程
const { ipcMain } = require('electron');
ipcMain.on("render2Mainsg",(event,arg) => {
console.log("渲染进程传递过来的数据",arg)
event.sender.send("main2render","主进程收到渲染进程发的异步消息")})
渲染进程给主进程发送同步消息
//渲染进程
const { ipcRenderer } = require('electron');
const msg = ipcRenderer.sendSync('msg-a');
console.log(msg)
//主进程
ipcMain.on('msg-a',(event)=> { event.returnValue = 'hello'; })
主进程通知渲染进程执行操作
//主进程
BrowserWindow.getFocusedWindow().webContents.send('replay','new 111');
//渲染进程
const { ipcRenderer } = require('electron');
ipcRenderer.on('reply', function(event, arg) { console.log(arg);});
渲染进程和渲染进程之间通信
- LocalStorage使数据两个html页面之间传递数据
- 通过 BrowserWindow 和 webContents 模块实现渲染进 程和渲染进程的通信
https://www.electronjs.org/docs/api/web-contents
每个新窗口都是一个新的html页面,都对应一个窗口对象,可以通过下面的方式获取每个窗口的id
const winId = BrowserWindow.getFocusedWindow().id;
let win = BrowserWindow.fromId(winId); //获取到对应id的BroswerWindow对象
//在index.html开启打开另一个窗口的权限
let indexWinId ;
ipcMain.on("openNews",(event,data)=>{//渲染进程发出打开另一个窗口的事件:openNews
indexWinId = BrowserWindow.getFocusedWindow().id;
const newsWindow= new BrowserWindow({
width: 800,
height: 600,
webPreferences:{
nodeIntegration:true,
enableRemoteModule:true
}
});
//在渲染进程中开启调试模式
newsWindow.webContents.openDevTools()
newsWindow.loadFile(path.join(__dirname, "news.html"));
//监听当前窗口加载完成的事件
newsWindow.webContents.on('did-finish-load',(event) => {
newsWindow.webContents.send('msg',winId,'我是 index.html 的数据'+data);
})
}
//主进程通过index.html的winID给index.html渲染进程回消息
let mainWin = BrowserWindow.fromId(indexId);
mainWin.webContents.send("toIndex",data)
Electron 中嵌入网页
https://www.electronjs.org/docs/api/shell //打开网页
https://www.electronjs.org/docs/tutorial/web-embeds //嵌入网页
var {shell}=require('electron') ;
shell.openExternal('https://github.com');
Important Note: we do not recommend you to use WebViews, as this tag undergoes dramatic architectural changes that may affect stability of your application. Consider switching to alternatives, like
iframe
and Electron'sBrowserView
, or an architecture that avoids embedded content by design.
官方建议使用iframe代替作为显示网页的容器
electron对话框
https://www.electronjs.org/docs/api/dialog
任务栏图标及菜单右键
https://www.electronjs.org/docs/api/tray
var { Menu, Tray,app,BrowserWindow } = require('electron');
var appIcon = new Tray(path.join(__dirname,'logo.png'));
const menu = Menu.buildFromTemplate( [
{ label: '设置', click: function () {} },
{ label: '退出', click: function () { //
BrowserWindow.getFocusedWindow()
.webContents()
.send('close-main-window');
app.quit();
}
}
]);
appIcon.setToolTip('logo 鼠标移入title');
appIcon.setContextMenu(menu);
应用窗口
https://www.electronjs.org/docs/api/browser-window
- 窗口关闭 :close
- 最小化事件: 'minimize'
- 事件: 'maximize'
const currWindow= BrowserWindow.getFocusedWindow();
currWindow.on('close',(e)=>{
if(!currWindow.isFocused()){
currWindow=null;
}else{
e.preventDefault(); /*阻止应用退出*/
currWindow.hide(); /*隐藏当前窗口*/
}
})
全局快捷键&剪贴板
https://www.electronjs.org/docs/api/global-shortcut
https://www.electronjs.org/docs/api/clipboard
globalShortcut 模块可以在操作系统中注册/注销全局快捷键, 以便可以为操作定制各种快捷键
隐藏工具栏和自定义窗口操作区域
var mainWindow = new BrowserWindow({
height: 620,
useContentSize: true,
width: 1280 ,
frame: false /*去掉顶部导航 去掉关闭按钮 最大化最小化按钮*/
});
mainWindow.setMenu(null)
自定义最大,最小,关闭
const { ipcMain, BrowserWindow } = require("electron");
//window-min,window-max',window-close是渲染进程发送过来的自定义消息
ipcMain.on('window-min',function(){ mainWindow.minimize(); })//登录窗口最大化
ipcMain.on('window-max',function(){ if(mainWindow.isMaximized()){ mainWindow.restore(); }else{mainWindow.maximize(); } })
ipcMain.on('window-close',function(){ mainWindow.close(); })
自定义可拖拽区域
可拖拽的 css: -webkit-app-region: drag;
不可拖拽的 css: -webkit-app-region: no-drag;