创建你的第一个应用:

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. 【读书笔记】知易行难,多实践

    前言: 其实,我不喜欢看书,只是喜欢找答案,想通过专业的解答来解决我生活的困惑.所以,我听了很多书,也看了很多书,但看完书,没有很多的实践,导致我并不很深入在很多时候. 分享读书笔记: <高效1 ...

  2. 【运维学习笔记】生命不息,搞事开始。。。

    001生命不息,搞事不止!!! 这段时间和hexesdesu搞了很多事情! 之前是机械硬盘和固态硬盘的测速,我就在那默默的看着他一个硬盘一个机械测来测去. 坐在他后面,每天都能看到这位萌萌的小男孩,各 ...

  3. SSAN 关系抽取 论文笔记

    20210621 https://zhuanlan.zhihu.com/p/353183322 [KG笔记]八.文档级(Document Level)关系抽取任务 共指id嵌入一样 但是实体嵌入的时候 ...

  4. pandas以前笔记

    # -*- coding: utf-8 -*- """ Created on Sat Jul 21 20:06:20 2018@author: heimi "& ...

  5. PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 call

    您的位置 首页 PyTorch 学习笔记系列 PyTorch 学习笔记(六):PyTorch hook 和关于 PyTorch backward 过程的理解 发布: 2017年8月4日 7,195阅读 ...

  6. 容器云原生DevOps学习笔记——第三期:从零搭建CI/CD系统标准化交付流程

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  7. 容器云原生DevOps学习笔记——第二期:如何快速高质量的应用容器化迁移

    暑期实习期间,所在的技术中台-效能研发团队规划设计并结合公司开源协同实现符合DevOps理念的研发工具平台,实现研发过程自动化.标准化: 实习期间对DevOps的理解一直懵懵懂懂,最近观看了阿里专家带 ...

  8. 王道考研 计算机网络笔记 第六章:应用层

    本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...

  9. 王道考研 计算机网络笔记 第五章:传输层

    本文基于2019 王道考研 计算机网络: 2019 王道考研 计算机网络 个人笔记总结 第一章:王道考研 计算机网络笔记 第一章:概述&计算机网络体系结构 第二章:王道考研 计算机网络笔记 第 ...

最新文章

  1. 选课系统html页面设计,网上选课系统的设计与实现(代码)..doc
  2. 如何用VS2017打开VS2010(低版本)文件
  3. [机器学习]AutoML --- NNI (Microsoft)
  4. JEECG近期会开展培训公开课
  5. 消息称苹果关联公司1.25亿美元购买车辆测试场 占地超过3万亩
  6. 话唠黄金机器人_用了接吻教学机器人以后......哈哈哈哈不能我一个人瞎!
  7. 动视服务器状态,《使命召唤12》A.B.C服务器错误不用怕 动视给你支招
  8. 鼠标功能不全?这几款鼠标增强辅助工具Mac App不能错过
  9. linux 中软件安装的三种方法
  10. FastAPI用户安全性解决方案
  11. 浙江大学计算机专业介绍,浙江大学计算机科学与技术专业课程设置
  12. 呼和浩特php平均工资,2019年内蒙古平均工资出炉
  13. 微软Kinect是怎么做到的
  14. 基于opencv python 的网线线序识别(三)
  15. 飞龙在天之DB面试资料
  16. GPS之MTK平台代码小结以及gps协议注释
  17. 买个云服务器搭建自己的ngrok做微信公众号开发
  18. 超材料常用的仿真软件CST COMSOL HFSS指导实际操作
  19. 兼容ie8及其以上IE浏览器,360浏览器,QQ浏览器等双核浏览器。
  20. 11种QQ技术 ,让你成为QQ高手

热门文章

  1. PHPMyWind支持PDF粘贴
  2. socket服务器区分各个客户端信息,socket服务器如何区分哪个客户端
  3. 解决MATLAB中0与o,1与l难以分辨
  4. news html5 qq,WebQQ全面升级支持IE9 HTML5无处不在
  5. 接口做的好怎么形容_9个色彩搭配网站,没当过设计师也能做好配色了
  6. 冬季高校寝室用电安全管理与防范
  7. 2020计算机数电实验第四次(2)
  8. 混IT,必须理解“甲方乙方”
  9. php实训日记200字,做实验日记200字
  10. dpdk-l3fwd 快速使用