electron_笔记
创建你的第一个应用:
package.json
:
{"name": "my-electron-app","version": "1.0.0","description": "my demo","main": "main.js","scripts": {"dev": "electron . --inspect=5858","start": "electron-forge start","package": "electron-forge package","make": "electron-forge make","win": "electron-builder --win --x64"},"author": "icestone","license": "MIT","devDependencies": {"@electron-forge/cli": "^6.1.1","electron": "23.1.3","electron-builder": "^23.6.0"},"win": {"icon": "icons/icon.ico","target": [{"target": "nsis","arch": ["x64","ia32"]}]}
}
main.js
const path = require('path');
const {app, BrowserWindow, ipcMain} = require('electron');const createWindow = () => {const win = new BrowserWindow({width: 1000,height: 900,webPreferences: {preload: path.join(__dirname, './preload.js'),},})require('./src/js/menu'),ipcMain.handle('ping', () => 'pong');win.loadFile('index.html');
}// 下面两种监听都可以
/*app.whenReady().then(() => {createWindow()
})*/
app.on('ready', () => {createWindow()
})// 监听关闭时调用
app.on('window-all-closed', () => {console.log('close window')if (process.platform !== 'darwin') app.quit()
})
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><title>Hello World!</title><meta http-equiv="Content-Security-Policy" content="script-src 'self' 'unsafe-inline';" />
</head>
<body>
<h1>Hello World!</h1>
<p>We are using Node.js <span id="node-version"></span>,Chromium <span id="chrome-version"></span>,and Electron <span id="electron-version"></span>.
</p>
</body>
</html>
run:
监听一个窗口的关闭:
win.on('close',function () {console.log('window is close!')})
它的完整代码应该是:
const path = require('path');
const {app, BrowserWindow, ipcMain} = require('electron');const createWindow = () => {const win = new BrowserWindow({width: 1000,height: 900,webPreferences: {preload: path.join(__dirname, './preload.js'),},})ipcMain.handle('ping', () => 'pong');win.loadFile('index.html');win.on('close',function () {console.log('window is close!')})
}// 下面两种监听都可以
/*app.whenReady().then(() => {createWindow()
})*/
app.on('ready', () => {createWindow()
})// 监听关闭时调用
app.on('window-all-closed', () => {console.log('close window')if (process.platform !== 'darwin') app.quit()
})
electron的生命周期
生命周期事件:
ready
- app初始化完成时调用一次
dom-ready
- 一个窗口中的文本加载完成,此时可以执行dom操作
did-finsh-load
- 导航完成时触发
window-all-closed
- 所有窗口都被关闭时触发
before-quit
- 在关闭窗口之前触发
will-quit
- 在窗口关闭并且应用退出时触发
quit
- 当所有窗口被关闭时触发
closed
- 当所有窗口关闭时触发,此时应删除窗口引用
例如下面的main.js演示:
const path = require('path');
const {app, BrowserWindow, ipcMain} = require('electron');const createWindow = () => {const win = new BrowserWindow({width: 1000,height: 900,webPreferences: {preload: path.join(__dirname, './preload.js'),},})ipcMain.handle('ping', () => 'pong');win.loadFile('index.html');win.webContents.on('did-finish-load', () => {console.log('did-finish-load');})win.webContents.on('dom-ready', () => {console.log('dom-ready');})win.on('close', function () {console.log('close')})
}// 下面两种监听都可以
/*app.whenReady().then(() => {createWindow()
})*/
app.on('ready', () => {console.log('ready')createWindow()
});
// 监听关闭时调用
app.on('window-all-closed', () => {console.log('all close window')if (process.platform !== 'darwin') app.quit()
});
app.on('before-quit', function () {console.log('before-quit')
});
app.on('will-quit', function () {console.log('will-quit');
});
app.on('quit', function () {console.log('quit');
});
run:
窗口尺寸设置
使用nodemon
package.json中的script:
"scripts": {"dev": "electron . --inspect=5858","start": "electron .","nodemon": "nodemon --main.js --exec npm run dev"},
这样就可以使用nodemon监听main.js的改动了
相关属性
每次打开窗口默认会在屏幕的中央进行显示,如果想要更改,可以在mian.js中使用x
,y
来更改:
const path = require('path');
const {app, BrowserWindow, ipcMain} = require('electron');const createWindow = () => {const win = new BrowserWindow({x: 200,y: 200,width: 1000,height: 900,webPreferences: {preload: path.join(__dirname, './preload.js'),},})ipcMain.handle('ping', () => 'pong');win.loadFile('index.html');win.webContents.on('did-finish-load', () => {console.log('did-finish-load');})win.webContents.on('dom-ready', () => {console.log('dom-ready');})win.on('close', function () {console.log('close')})
}// 下面两种监听都可以
/*app.whenReady().then(() => {createWindow()
})*/
app.on('ready', () => {console.log('ready')createWindow()
});
// 监听关闭时调用
app.on('window-all-closed', () => {console.log('all close window')if (process.platform !== 'darwin') app.quit()
});
app.on('before-quit', function () {console.log('before-quit')
});
app.on('will-quit', function () {console.log('will-quit');
});
app.on('quit', function () {console.log('quit');
});
然后他就更改了:
但是此时,可能会先出现窗口,白屏一瞬间之后再加载内容,那么此时就可以使用:show: false
设置一下
const win = new BrowserWindow({show: false,x: 200,y: 200,width: 1000,height: 900,webPreferences: {preload: path.join(__dirname, './preload.js'),},})win.on("ready-to-show", function () {win.loadFile('index.html');})
这里监听了ready-to-show
,在这个阶段才调用加载index.html
设置最大,最小尺寸
const win = new BrowserWindow({show: false,x: 200,y: 200,width: 1000,height: 900,maxHeight: 1000,maxWidth: 1100,minHeight: 500,minWidth: 1000})
固定尺寸
使用resizable:false
:
const win = new BrowserWindow({show: false,x: 200,y: 200,width: 1000,height: 900,maxHeight: 1000,maxWidth: 1100,minHeight: 500,minWidth: 1000,resizable:false})
main设置界面内容
设置title
const win = new BrowserWindow({// show: false,x: 200,y: 200,width: 1000,height: 900,// 设置最大尺寸maxHeight: 1000,maxWidth: 1100,// 设置最小尺寸minHeight: 500,minWidth: 1000,// 禁止缩放窗口// resizable:falsetitle:'在main.js中设置的title'})
- 注意,此时在index.html的title应该为空
设置icon
const win = new BrowserWindow({// show: false,x: 200,y: 200,width: 1000,height: 900,// 设置最大尺寸maxHeight: 1000,maxWidth: 1100,// 设置最小尺寸minHeight: 500,minWidth: 1000,// 禁止缩放窗口// resizable:falsetitle:'在main.js中设置的title',icon:'./lg.ico'})
如图:
不显示默认的窗口和菜单
frame:false
,默认为true
运行:
那么此时窗口无法进行拖动
透明窗体
transparent: true
运行:
隐藏menu
const win = new BrowserWindow({// show: false,x: 200,y: 200,width: 1000,height: 900,// 设置最大尺寸maxHeight: 1000,maxWidth: 1100,// 设置最小尺寸minHeight: 500,minWidth: 1000,// 禁止缩放窗口// resizable:falsetitle: '在main.js中设置的title',icon: './lg.ico',// 不显示默认窗口和菜单// frame:false// 透明窗体// transparent: true// 隐藏menuautoHideMenuBar: true})
调试面板
ctrl+shift+i
允许渲染进程和nodejs交互
一般情况下,在index.html
中引用的js文件是无法导入nodejs中的包的,例如下面的代码:
index.js
:
const o = require('electron');// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {// 点击打开一个新窗口const oBtn = document.getElementById('btn')oBtn.addEventListener('click', () => {})
})
在第一行导入了包,那么在应用的控制台中:
默认情况下是不允许渲染进程中的js直接和nodejs进行交互,那么在开发中想要和nodejs进行交互,可以在main.js中开启:
webPreferences: {nodeIntegration: true,contextIsolation
:false
}
完整的main.js:
const path = require('path');
const {app, BrowserWindow, ipcMain} = require('electron');const createWindow = () => {const win = new BrowserWindow({x: 200,y: 200,width: 1000,height: 900,title: '在main.js中设置的title',icon: './lg.ico',autoHideMenuBar: true,webPreferences: {nodeIntegration: true,contextIsolation: false}})win.loadFile('index.html');
}// 监听关闭时调用
app.on('window-all-closed', () => {console.log('all close window')if (process.platform !== 'darwin') app.quit()
});
然后就不会报错了
渲染进程中不可以使用主进程的一些对象
例如像下面,在渲染进程中使用了BrowserWindow
,虽然可以导入,但是不被允许:
// BrowserWindow 是个主进程,虽然可以导入,但是在渲染进程中是不允许这样做的
const {BrowserWindow} = require('electron');
// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {// 点击打开一个新窗口const oBtn = document.getElementById('btn')oBtn.addEventListener('click', () => {let indexMin = new BrowserWindow({width: 1000,height: 900})indexMin.loadFile('../views/list.html');indexMin.on("close", () => {indexMin = null;})})
})
报错:
index.js:8 Uncaught TypeError: BrowserWindow is not a constructorat HTMLButtonElement.<anonymous> (index.js:8:24)
使用remote让渲染进程使用BrowserWindow
main.js中的主要代码:
const remote = require("@electron/remote/main") //1
remote.initialize()//2
remote.enable(win.webContents)//3
mian.js
的完整代码:
const {app, BrowserWindow} = require('electron');
const remote = require("@electron/remote/main") //1
remote.initialize()//2const createWindow = () => {const win = new BrowserWindow({x: 200,y: 200,width: 1000,height: 900,title: '在main.js中设置的title',icon: './lg.ico',autoHideMenuBar: true,webPreferences: {nodeIntegration: true,contextIsolation: false},})win.loadFile('index.html');remote.enable(win.webContents)//3
}app.on('ready', () => {console.log('ready')createWindow()
});
// 监听关闭时调用
app.on('window-all-closed', () => {console.log('all close window')if (process.platform !== 'darwin') app.quit()
});
index.js
:
// BrowserWindow 是个主进程,虽然可以导入,但是在渲染进程中是不允许这样做的
const {BrowserWindow} = require("@electron/remote");
console.log('当前路径')
console.log(__dirname)
// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {// 点击打开一个新窗口const oBtn = document.getElementById('btn')oBtn.addEventListener('click', () => {let indexMin = new BrowserWindow({width: 1000,height: 900})indexMin.loadFile('./src/views/list.html');indexMin.on("close", () => {indexMin = null;})})
})
要注意这里的引用:
const {BrowserWindow} = require("@electron/remote");
自定义窗口的实现
最小化,最大化,关闭的实现:
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><!-- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP --><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title><!-- <link rel="stylesheet/less" type="text/less" href="./src/css/index.less"/>--><link rel="stylesheet" type="text/css" href="./src/css/index.css"/>
</head>
<body>
<div class="container"><div class="header"><div class="btn">minWindow</div><div class="btn">maxWindow</div><div class="btn">close</div></div></div><script src="./index.js"></script></body>
</html>
index.js
:
// BrowserWindow 是个主进程,虽然可以导入,但是在渲染进程中是不允许这样做的
const {BrowserWindow, ipcMain, getCurrentWindow} = require("@electron/remote");
let mainWin = getCurrentWindow();console.log('当前路径')
console.log(__dirname)
// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {// 点击打开一个新窗口const btns = document.getElementsByClassName('btn')const close = btns[2];const maxWindow = btns[1];const minWindow = btns[0];close.addEventListener('click', () => {console.log('关闭')mainWin.close();})maxWindow.addEventListener('click', () => {console.log('最大化')/* console.log('是否为最大化')console.log(mainWin.isMaximizable());*/if (!mainWin.isMaximized()) {mainWin.maximize()} else {console.log('恢复尺寸')// 让当前窗口回到原始状态mainWin.restore();}})minWindow.addEventListener('click', () => {console.log('最小化')if (!mainWin.isMinimized()) {mainWin.minimize()} else {mainWin.restore();}})
})
阻止窗口关闭
监听窗口关闭之前的状态:
index.js
:
// BrowserWindow 是个主进程,虽然可以导入,但是在渲染进程中是不允许这样做的
const {BrowserWindow, ipcMain, getCurrentWindow} = require("@electron/remote");
let mainWin = getCurrentWindow();console.log('当前路径')
console.log(__dirname)
// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {window.onbeforeunload = function () {console.log('关闭窗口')return false;}// 点击打开一个新窗口const btns = document.getElementsByClassName('btn')const close = btns[2];const maxWindow = btns[1];const minWindow = btns[0];close.addEventListener('click', () => {console.log('关闭')mainWin.close();})maxWindow.addEventListener('click', () => {console.log('最大化')/*console.log('是否为最大化')console.log(mainWin.isMaximizable());*/if (!mainWin.isMaximized()) {mainWin.maximize()} else {console.log('恢复尺寸')// 让当前窗口回到原始状态mainWin.restore();}})minWindow.addEventListener('click', () => {console.log('最小化')if (!mainWin.isMinimized()) {mainWin.minimize()} else {mainWin.restore();}})
})
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title><link rel="stylesheet" type="text/css" href="./src/css/index.css"/>
</head>
<body>
<div class="container"><div class="header"><div class="btn">minWindow</div><div class="btn">maxWindow</div><div class="btn">close</div></div></div>
<div class="alert">确认关闭?<button class="close">yes!</button><button class="notClose">no!</button>
</div>
<script src="./index.js"></script>
</body>
</html>
这里主要是index.js
中的:
window.onbeforeunload = function () {console.log('关闭窗口')return false;
}
弹窗控制窗口关闭与否:
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title><link rel="stylesheet" type="text/css" href="./src/css/index.css"/>
</head>
<body>
<div class="container"><div class="header"><div class="btn">minWindow</div><div class="btn">maxWindow</div><div class="btn">close</div></div>
</div>
<div class="alert">确认关闭?<button class="close">yes!</button><button class="notClose">no!</button>
</div>
<script src="./index.js"></script>
</body>
</html>
index.css
:
.container {display: flex;flex-direction: column;
}.header {display: flex;width: 100%;flex-direction: row;justify-content: end;background: #8c8c73;
}.header div {padding-right: 20px;
}body {background-image: linear-gradient(to top, #cfd9df 0%, #e2ebf0 100%);
}.alert {display: none;
}
index.js
:
// BrowserWindow 是个主进程,虽然可以导入,但是在渲染进程中是不允许这样做的
const {BrowserWindow, ipcMain, getCurrentWindow} = require("@electron/remote");
let mainWin = getCurrentWindow();console.log('当前路径')
console.log(__dirname)
// dom加载完之后执行
window.addEventListener('DOMContentLoaded', function () {window.onbeforeunload = function () {console.log('关闭窗口')const alert = document.getElementsByClassName('alert')[0];alert.style.display = 'flex';const yesBtn = document.getElementsByClassName('close')[0];const noBtn = document.getElementsByClassName('notClose')[0];yesBtn.addEventListener('click', () => {mainWin.destroy();})noBtn.addEventListener('click', () => {alert.style.display = 'none';})return false;}// 点击打开一个新窗口const btns = document.getElementsByClassName('btn')const close = btns[2];const maxWindow = btns[1];const minWindow = btns[0];close.addEventListener('click', () => {console.log('关闭')mainWin.close();})maxWindow.addEventListener('click', () => {console.log('最大化')/*console.log('是否为最大化')console.log(mainWin.isMaximizable());*/if (!mainWin.isMaximized()) {mainWin.maximize()} else {console.log('恢复尺寸')// 让当前窗口回到原始状态mainWin.restore();}})minWindow.addEventListener('click', () => {console.log('最小化')if (!mainWin.isMinimized()) {mainWin.minimize()} else {mainWin.restore();}})
})
main.js
:
const {app, BrowserWindow} = require('electron')
const path = require('path')
const remote = require("@electron/remote/main") //1
remote.initialize()//2
const createWindow = () => {const win = new BrowserWindow({width: 800,height: 600,frame: false,webPreferences: {nodeIntegration: true,contextIsolation: false}})win.loadFile('index.html')win.on('close', function () {console.log('close')})remote.enable(win.webContents)//3
}
app.whenReady().then(() => {createWindow()app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
父子及模态窗口
一般情况下创建的子窗口,在操作子窗口时,父窗口依旧可以操作:
main.js
:
const {app, BrowserWindow} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '子窗口及模态窗口',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
index.html
:
<!--index.html-->
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title>
</head>
<body><div class="container"><button id="btn">新增窗口</button></div>
<script src="./index.js"></script>
</body>
</html>
index.js
:
const {BrowserWindow, getCurrentWindow} = require("@electron/remote");
let mainWin = getCurrentWindow();
window.addEventListener('DOMContentLoaded', () => {const btn = document.getElementById("btn");btn.addEventListener('click', () => {let subWin = new BrowserWindow({parent: mainWin,width: 1000,height: 900})subWin.loadFile('sub.html')subWin.on('close', () => {subWin = null;})})
})
run:
此时是可以拖动父窗口的
但是使用模态窗口就可以避免这个问题,
模态窗口
main.js
:
const {app, BrowserWindow} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '子窗口及模态窗口',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
index.html
:
<!--index.html-->
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title>
</head>
<body><div class="container"><button id="btn">新增窗口</button></div>
<script src="./index.js"></script>
</body>
</html>
index.js
:
const {BrowserWindow, getCurrentWindow} = require("@electron/remote");
let mainWin = getCurrentWindow();
window.addEventListener('DOMContentLoaded', () => {const btn = document.getElementById("btn");btn.addEventListener('click', () => {let subWin = new BrowserWindow({parent: mainWin,width: 1000,height: 900,modal: true})subWin.loadFile('sub.html')subWin.on('close', () => {subWin = null;})})
})
run:
注意,这里主要起作用的是index.js
的:
modal: true
自定义菜单
自定义一个简单的菜单
const {app, BrowserWindow, Menu} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()
const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '自定义菜单',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 1.定义自己需要的菜单let menuMap = [{label: '文件'},{label: '编辑'},];// 2.利用上面的模板构建菜单项:let menu = Menu.buildFromTemplate(menuMap);// 3.将上述的自定义菜单添加到应用Menu.setApplicationMenu(menu);win.loadFile('index.html')//3remote.enable(win.webContents)
}
app.whenReady().then(() => {createWindow()app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})
app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
主要分三步:
- 定义你的菜单,数组,需要在之前引入Menu:
const {app, BrowserWindow, Menu} = require('electron')
// 1.定义自己需要的菜单
let menuMap = [{label: '文件'},{label: '编辑'},
];
- 利用上面的模板构建菜单项:
let menu = Menu.buildFromTemplate(menuMap);
- 将上述的自定义菜单添加到应用
// 3.将上述的自定义菜单添加到应用
Menu.setApplicationMenu(menu);
win.loadFile('index.html')
菜单的点击以及二级菜单
const {app, BrowserWindow, Menu} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()
const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '自定义菜单',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 1.定义自己需要的菜单let menuMap = [{label: '文件',submenu: [{label: '打开文件夹',click() {console.log('open someone dir')}},{label: '打开文件'},{label: '关于',role: 'about'}]},{label: '编辑'},];// 2.利用上面的模板构建菜单项:let menu = Menu.buildFromTemplate(menuMap);// 3.将上述的自定义菜单添加到应用Menu.setApplicationMenu(menu);// 加载 index.htmlwin.loadFile('index.html')//3remote.enable(win.webContents)
}
app.whenReady().then(() => {createWindow()app.on('activate', () => {if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
这里主要是menuMap
发生变化,里面存储的click
函数,在文件
中定义的有其他的二级菜单
定义菜单之间的分割线
let menuMap = [{label: '文件',submenu: [{label: '打开文件夹',click() {console.log('open someone dir')}},// 分割线{type: 'separator'},{label: '打开文件',},{label: '关于',role: 'about'}]},{label: '编辑'},
];
例如上面的,传入type`的值表示不同的分割线
角色菜单以及类型
菜单中的内置角色
let menuMap = [{label: '内置角色',submenu: [{label: '复制',role: 'copy'},{label: '剪贴',role: 'cut'},{label: '粘贴',role: 'paste'},{label: '最小化',role: 'minimize'}]}];
菜单中的选项卡:
let menuMap = [{label: '类型',submenu: [{label: '选项1',type: 'checkbox'},{label: '选项2',type: 'checkbox'},{label: '选项3',type: 'checkbox'},{type: 'separator'},{label: 'item1',type: 'radio'},{label: 'item2',type: 'radio'},{type: 'separator'},{label: 'windows',type: 'submenu',role: 'windowMenu'}]}]
快捷键
let menuMap = [{label: '其他',submenu: [{label: '打开',icon: './open.png',accelerator: 'ctrl+o',click() {console.log('open操作执行了!')}},]}
]
动态创建菜单
main.js
:
const {app, BrowserWindow} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: 'demo页面',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title>
</head>
<body>
<h1>自定义菜单</h1>
<div class="container"><button id="add">创建自定义菜单</button><input type="text" value="输入自定义菜单项内容" id="menuVal"><button id="addMenu">添加菜单项</button></div>
<script src="./index.js"></script>
</body>
</html>
index.js
:
const {BrowserWindow, Menu, MenuItem} = require("@electron/remote");console.log('当前路径')
console.log(__dirname)
// 自定义全局变量
let menuItem = new Menu();window.addEventListener('DOMContentLoaded', () => {let addBtn = document.getElementById('add');let addMenuBtn = document.getElementById('addMenu');let input = document.getElementById('menuVal');// 生成自定义的菜单:addBtn.addEventListener('click', () => {// 创建菜单let menuFile = new MenuItem({label: '文件', type: 'normal'});let menuEdit = new MenuItem({label: '编辑', type: 'normal'});let customMenu = new MenuItem({label: '自定义菜单', submenu: menuItem});
// 将创建好的菜单添加至menulet menu = new Menu();menu.append(menuFile)menu.append(menuEdit)menu.append(customMenu)
// 将menu放置于app中显示Menu.setApplicationMenu(menu);})addMenuBtn.addEventListener('click', () => {// 获取当前input输入框的内容const con = input.value.trim();if (con) {menuItem.append(new MenuItem({label: con, type: 'normal'}))input.value = '';}})
})
运行:
右键菜单
mian.js
:
const {app, BrowserWindow} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '右键菜单',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})
index.html
:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title>
</head>
<body>
<h1>你好!</h1>
<div class="container"></div>
<script src="./index.js"></script>
</body>
</html>
index.js
:
const {Menu, getCurrentWindow} = require("@electron/remote");
const remote = require("@electron/remote/main")
let mainWin = getCurrentWindow();// 创建一个自定义的菜单内容
let contextTemp = [{label: 'Run Code'},{label: '转到定义'},{type: 'separator'},{label: '其他功能',click() {console.log('其他功能被点击了')}},
]
// 依据上面模板来创建menu
let menu = Menu.buildFromTemplate(contextTemp);// 在鼠标右击行为后显示出来
window.addEventListener('DOMContentLoaded', () => {// 监听右击window.addEventListener('contextmenu', (ev) => {ev.preventDefault();menu.popup({window: mainWin})}, false)
})
运行:
主进程与渲染进程之间通讯
监听页面元素点击,渲染进程向主进程发消息:
渲染进程向主进程发送消息
index.html
<button id="one">渲染到主异步操作</button><br><button id="two">渲染到主同步操作</button>
index.js
const {ipcRenderer
} = require('electron')window.onload = function () {const aBtn = document.getElementById('one');const twoBtn = document.getElementById('two');
// 异步发送消息
// 通过异步api在渲染进程中给主进程发送消息aBtn.addEventListener('click', () => {ipcRenderer.send('msg1', '来自渲染进程的异步消息');})
// 接收来自主进程的异步消息ipcRenderer.on('msg1Re', (ev, data) => {console.log('来自主进程的data:')console.log(data)})
// 同步发送消息twoBtn.addEventListener('click', () => {let val = ipcRenderer.sendSync('msg2', '同步消息')console.log("val:")console.log(val)})
}
main.js
const {app, BrowserWindow, ipcMain, Menu} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()let temp = [{label: 'send',click() {BrowserWindow.getFocusedWindow().webContents.send('mtp','来自于主进程的消息')}}
]
let menu = Menu.buildFromTemplate(temp);
Menu.setApplicationMenu(menu);const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '主进程与渲染进程之间通讯',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')win.webContents.openDevTools();//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})// 主进程接受消息
ipcMain.on('msg1', (ev, data) => {console.log('data:')console.log(data)
// 给渲染进程发送消息ev.sender.send('msg1Re', '这是一条来自主进程的异步消息')
})
ipcMain.on('msg2', (ev, data) => {console.log(data)ev.returnValue = '来自于主进程的同步消息'
})
上面代码中主要是ipcMain.on
来接收渲染进程发送来的消息
主进程接收消息后向渲染进程发送消息
主进程可以这样接收并返回:
ipcMain.on('msg1', (ev, data) => {console.log('data:')console.log(data)// 给渲染进程发送消息ev.sender.send('msg1Re', '这是一条来自主进程的异步消息')
})
ipcMain.on('msg2', (ev, data) => {console.log(data)// 给渲染进程发送消息ev.returnValue = '来自于主进程的同步消息'
})
渲染进程的接收:
ipcRenderer.on('msg1Re', (ev, data) => {console.log('来自主进程的data:')console.log(data)})
// 同步发送消息twoBtn.addEventListener('click', () => {let val = ipcRenderer.sendSync('msg2', '同步消息')console.log("val:")console.log(val)})
上面的代码中,渲染进程向主进程发送消息,并接收
主线程向渲染进程发送消息
主线程
:
let temp = [{label: 'send',click() {BrowserWindow.getFocusedWindow().webContents.send('mtp','来自于主进程的消息')}}
]
let menu = Menu.buildFromTemplate(temp);
Menu.setApplicationMenu(menu);
上面的代码中,设置了一个点击事件,点击触发向当前获取焦点的窗口发送消息
渲染进程:
ipcRenderer.on('mtp', (ev, data) => {console.log(data)})
完成代码:
main.js
const {app, BrowserWindow, ipcMain, Menu} = require('electron')
//1
const remote = require("@electron/remote/main")
//2
remote.initialize()let temp = [{label: 'send',click() {BrowserWindow.getFocusedWindow().webContents.send('mtp','来自于主进程的消息')}}
]
let menu = Menu.buildFromTemplate(temp);
Menu.setApplicationMenu(menu);const createWindow = () => {// 创建浏览窗口const win = new BrowserWindow({width: 800,height: 600,title: '主进程与渲染进程之间通讯',webPreferences: {nodeIntegration: true,contextIsolation: false}})// 加载 index.htmlwin.loadFile('index.html')win.webContents.openDevTools();//3remote.enable(win.webContents)// 打开开发工具// mainWindow.webContents.openDevTools()
}// 这段程序将会在 Electron 结束初始化
// 和创建浏览器窗口的时候调用
// 部分 API 在 ready 事件触发后才能使用。
app.whenReady().then(() => {createWindow()app.on('activate', () => {// 在 macOS 系统内, 如果没有已开启的应用窗口// 点击托盘图标时通常会重新创建一个新窗口if (BrowserWindow.getAllWindows().length === 0) createWindow()})
})app.on('window-all-closed', () => {if (process.platform !== 'darwin') app.quit()
})// 主进程接受消息
ipcMain.on('msg1', (ev, data) => {console.log('data:')console.log(data)
// 给渲染进程发送消息ev.sender.send('msg1Re', '这是一条来自主进程的异步消息')
})
ipcMain.on('msg2', (ev, data) => {console.log(data)ev.returnValue = '来自于主进程的同步消息'
})
index.js
const {ipcRenderer
} = require('electron')window.onload = function () {const aBtn = document.getElementById('one');const twoBtn = document.getElementById('two');
// 异步发送消息
// 通过异步api在渲染进程中给主进程发送消息aBtn.addEventListener('click', () => {ipcRenderer.send('msg1', '来自渲染进程的异步消息');})
// 接收来自主进程的异步消息ipcRenderer.on('msg1Re', (ev, data) => {console.log('来自主进程的data:')console.log(data)})
// 同步发送消息twoBtn.addEventListener('click', () => {let val = ipcRenderer.sendSync('msg2', '同步消息')console.log("val:")console.log(val)})ipcRenderer.on('mtp', (ev, data) => {console.log(data)})
}
index.html
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'"><title></title>
</head>
<body>
<h1>渲染进程与主进程通信</h1>
<div class="container"><button id="one">渲染到主异步操作</button><br><button id="two">渲染到主同步操作</button>
</div>
<script src="./index.js"></script>
</body>
</html>
基于本地存储的渲染进程通信
electron_笔记相关推荐
- 【读书笔记】知易行难,多实践
前言: 其实,我不喜欢看书,只是喜欢找答案,想通过专业的解答来解决我生活的困惑.所以,我听了很多书,也看了很多书,但看完书,没有很多的实践,导致我并不很深入在很多时候. 分享读书笔记: <高效1 ...
- 【运维学习笔记】生命不息,搞事开始。。。
001生命不息,搞事不止!!! 这段时间和hexesdesu搞了很多事情! 之前是机械硬盘和固态硬盘的测速,我就在那默默的看着他一个硬盘一个机械测来测去. 坐在他后面,每天都能看到这位萌萌的小男孩,各 ...
- SSAN 关系抽取 论文笔记
20210621 https://zhuanlan.zhihu.com/p/353183322 [KG笔记]八.文档级(Document Level)关系抽取任务 共指id嵌入一样 但是实体嵌入的时候 ...
- pandas以前笔记
# -*- coding: utf-8 -*- """ Created on Sat Jul 21 20:06:20 2018@author: heimi "& ...
- PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call
您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...
- 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程
暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...
- 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移
暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...
- 王道考研 计算机网络笔记 第六章:应用层
本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...
- 王道考研 计算机网络笔记 第五章:传输层
本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...
最新文章
- 选课系统html页面设计,网上选课系统的设计与实现(代码)..doc
- 如何用VS2017打开VS2010(低版本)文件
- [机器学习]AutoML --- NNI (Microsoft)
- JEECG近期会开展培训公开课
- 消息称苹果关联公司1.25亿美元购买车辆测试场 占地超过3万亩
- 话唠黄金机器人_用了接吻教学机器人以后......哈哈哈哈不能我一个人瞎!
- 动视服务器状态,《使命召唤12》A.B.C服务器错误不用怕 动视给你支招
- 鼠标功能不全?这几款鼠标增强辅助工具Mac App不能错过
- linux 中软件安装的三种方法
- FastAPI用户安全性解决方案
- 浙江大学计算机专业介绍,浙江大学计算机科学与技术专业课程设置
- 呼和浩特php平均工资,2019年内蒙古平均工资出炉
- 微软Kinect是怎么做到的
- 基于opencv python 的网线线序识别(三)
- 飞龙在天之DB面试资料
- GPS之MTK平台代码小结以及gps协议注释
- 买个云服务器搭建自己的ngrok做微信公众号开发
- 超材料常用的仿真软件CST COMSOL HFSS指导实际操作
- 兼容ie8及其以上IE浏览器,360浏览器,QQ浏览器等双核浏览器。
- 11种QQ技术 ,让你成为QQ高手