目录
前言
一、安装需知
二、安装electron
三、开始
3.1 修改package.json文件
3.2 创建main.js文件
3.3 启动预览窗口
3.4 显示内容
四、 热加载
五、主进程和渲染进程概念介绍
六、自定义原生菜单
6.1 自定义菜单
6.2 给菜单添加点击事件
6.3 抽离菜单定义
6.4 无边框菜单
6.4.1 为无边框菜单添加新建窗口点击事件
6.4.2 小总结
6.4.2 点击打开网页
七、打开对话框读取文件
前言
Electron是由GitHub众多开发者开发的一个开源项目,能够使用 JavaScript,HTML 和 CSS 构建跨平台的桌面应用程序。
当然了,它也可以与vue和react相结合。前端的小伙伴们,学习它应该很快,是很容易上手的一门技术。
文档编写不易,还请各位耐心观看。另外本人能力有限,如有不足之处,还请不吝批评指正!
一、安装需知
需要提前安装好Nodejs,因为Electron依赖于Nodejs。
注意二者有版本要求,比如Electron的v25.0.1版本就要求nodejs必须大于等于18.15.0版本。
所以安装之前建议去Electron的官网查看以下对应的版本。附上地址:Electron Releases
二、安装electron
个人推荐版本:
Node:v16.13.2 Electron:v18.1.0
初始化项目
新建一个文件夹,在文件夹内初始化项目
npm init
安装electron
注意安装时指定版本,否则就是安装的最新版本。一旦安装最新版本,倘若你们nodejs不是最新的,就有可能导致无法安装,提示让你下载更高版本的nodejs。
npm install electron@v18.1.0 --save-dev
检查是否安装成功
安装完成后,我们可以通过如下命令检验版本号来判断是否安装成功
npx electron -v
或者我们可以直接进入在根路径下执行如下命令打开程序,如果弹出应用程序,说明安装成功了。
./node_modules/.bin/electron
三、开始
上面出现的这个应用程序界面是electron内置的一个demo样例。
下面我们就正式开发一个属于自己的界面了。
3.1 修改package.json文件
我们项目初始化完成后,默认会生成一个package.json的文件。
我们需要在scripts对象中追加一个执行命令:
"scripts": {
"start": "electron ."
}
当然了,执行命令叫什么自己取都行,但是实际要执行的必须是electron .
其次,我们发现"main": "index.js",但是,我们并没有这个index.js,因此需要自己在根路径下新建该文件。为了符合electron的习惯,我们习惯上将index.js命名为main.js。它就是我们主程序的入口。
所以,修改后的package.json文件如下:
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"electron": "electron ."
},
"author": "",
"license": "ISC",
"devDependencies": {
"electron": "^18.1.0"
}
}
3.2 创建main.js文件
main.js作为程序的入口,我们应该怎么写呢?
直接看下面的代码,相关说明我都注释标注了。
// 导入electron对象
// app 控制应用程序的事件生命周期。
// BrowserWindow 创建并控制浏览器窗口。
const { app,BrowserWindow } = require('electron')
// 控制ready事件
// ready事件是:当 Electron 完成初始化时,发出一次。
app.on('ready',()=>{
// 新建窗口
new BrowserWindow({
width: 800,
height: 600
})
})
3.3 启动预览窗口
下面,我们执行启动命令查看一下:
npm run electron
ok,窗口成功创建出来了,我们接下来就是让他显示内容了。
3.4 显示内容
我们创建窗口之后,就可以获得这个窗口的返回对象。
通过这个返回对象,我们可以让它加载一个HTML页面,这就是electron显示内容的方式了。
// 导入electron对象
// app 控制应用程序的事件生命周期。
// BrowserWindow 创建并控制浏览器窗口。
const { app,BrowserWindow } = require('electron')
// 控制ready事件
// ready事件是:当 Electron 完成初始化时,发出一次。
app.on('ready',()=>{
// 新建窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600
});
// 让主窗口加载文件 html文件
mainWindow.loadFile('./src/index.html');
})
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<h1>欢迎来到electron</h1>
</body>
</html>
重新执行npm run electron启动,发现就成功的读取到了我们编写的index.html页面了。
四、 热加载
通过上面的案例我们发现,每次编写完代码都需要重新运行。这样就比较麻烦了,有没有办法让我们代码修改完成就直接能看到效果了?
这就是热加载功能。
安装十分简单:
npm install --save-dev electron-reloader
使用方法只需要在main.js的入口文件中引入即可:
// 开启热加载
const reloader = require('electron-reloader')
reloader(module)
五、主进程和渲染进程概念介绍
Electron 运行 package.json
的 main
脚本的进程被称为主进程。 在主进程中运行的脚本通过创建web页面来展示用户界面。 一个 Electron 应用总是有且只有一个主进程。
由于 Electron 使用了 Chromium 来展示 web 页面,所以 Chromium 的多进程架构也被使用到。 每个 Electron 中的 web 页面运行在它的叫渲染进程的进程中。也就是说每个页面都是渲染进程。
在普通的浏览器中,web页面无法访问操作系统的原生资源。 然而 Electron 的用户在 Node.js 的 API 支持下可以在页面中和操作系统进行一些底层交互。
ctrl+shift+i打开渲染进程调试
演示快捷键
六、自定义原生菜单
6.1 自定义菜单
electron默认为我们提供了菜单栏,如上所示。
如果我们不想使用默认的原生菜单,自定义也是可以的。
这需要我们先引入electron的menu菜单对象。
const { app,BrowserWindow,Menu} = require('electron')
然后我们自定义需要先配置模板,再通过模板创建出新的菜单对象,最后将菜单对象放到我们的Menu菜单对象中。
完整的代码为:
// 导入electron对象
// app 控制应用程序的事件生命周期。
// BrowserWindow 创建并控制浏览器窗口。
// Menu 创建原生应用菜单和上下文菜单。
const { app,BrowserWindow,Menu} = require('electron')
// 开启热加载
const reloader = require('electron-reloader')
reloader(module)
// 控制ready事件
// ready事件是:当 Electron 完成初始化时,发出一次。
app.on('ready',()=>{
// 新建窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600
});
// 让主窗口加载文件 html文件
mainWindow.loadFile('./src/index.html');
// 配置模板
const template = [
{
label: '文件'
},
{
label: '编辑'
},
{
label: '关于我们'
}
]
// 菜单对象构建该模板,生成菜单对象
const menu = Menu.buildFromTemplate(template);
// 设置我们构建好的菜单
Menu.setApplicationMenu(menu);
})
ok,我们的菜单栏就彻底改变了。
至于为什么模板中的键值为label,这个是官网要求的具体可查询相关api。Menu | Electron
ok,我们可以参考api丰富一下菜单,这里演示为文件菜单设置一些子菜单。
6.2 给菜单添加点击事件
接下来,我们实现一个功能,就是点击新建窗口的时候,让它弹出一个新的窗口。
实现起来也很容器,template中提供有click()方法来完成。
6.3 抽离菜单定义
为了方便后续维护,我们最好不把所有的功能都写在main.js中。比如菜单栏相关的代码,单独抽取成为一个menu.js。然后再引入到main.js中。
menu.js
const {BrowserWindow,Menu} = require('electron')
// 配置模板
const template = [
{
label: '文件',
submenu: [
{
label: '新建窗口',
click(){
new BrowserWindow({
width: 300,
height: 200
})
}
},
{
label: '保存'
},
{
label: '另存为'
},
{
label: '首选项'
},
{
label: '退出'
}
]
},
{
label: '编辑'
},
{
label: '关于我们'
}
]
// 菜单对象构建该模板,生成菜单对象
const menu = Menu.buildFromTemplate(template);
// 设置我们构建好的菜单
Menu.setApplicationMenu(menu);
main.js
// 导入electron对象
// app 控制应用程序的事件生命周期。
// BrowserWindow 创建并控制浏览器窗口。
// Menu 创建原生应用菜单和上下文菜单。
const { app,BrowserWindow} = require('electron')
// 开启热加载
const reloader = require('electron-reloader')
reloader(module)
// 控制ready事件
// ready事件是:当 Electron 完成初始化时,发出一次。
app.on('ready',()=>{
// 新建窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600
});
// 让主窗口加载文件 html文件
mainWindow.loadFile('./src/index.html');
// 引入自定义菜单
require('./menu')
})
界面效果依然一样,这里就不展示了。
6.4 无边框菜单
我们不用原生的这种菜单方式,像QQ音乐这种,菜单是自定义的。其实实现起来也不复杂。只需要隐藏掉frame即可,然后自己写菜单结构和样式。如下:
我们发现移走了是移走了,可是现在也无法拖拽了,也没有自己的菜单怎么办?
别急,我们一步一步来实现,先自定义菜单。
在index.html中写上菜单的html,然后再为它写一个css样式。
最后是使它能够拖拽,追加css:-webkit-app-region: drag; 实现拖拽。
6.4.1 为无边框菜单添加新建窗口点击事件
上面我们已经实现了无边框的菜单栏,并且让它拥有了可拖拽能力。
下面我们还是要实现一下点击新建窗口弹出一个新的窗口。
这时,问题来了,之前我们都是在主进程中也就是main.js文件中,通过BrowserWindow对象实现的。
现在我们的菜单栏是在index.html文件中实现的,它是在一个渲染进程中。渲染进程是无法操作主进程的对象的。
想在渲染进程中使用主进程中才能使用的对象,这就必须先remote出来。
ok,重新运行一下,发现点击并没有反应,我们打开调试窗口看看,结果发现报错了。
他说require is not defined。
这是因为JavaScript中默认是不能使用require这些属于nodejs的东西的。
如果想在JavaScript代码中使用nodejs的东西,就必须在主进程中开启node模块以及remote模块。
webPreferences: {
// 开启node模块
nodeIntegration: true,// 如果无法开启node模块,还是报这个错,那么请关闭下面这个配置项
contextIsolation: false,
// 开启remote模块
enableRemoteModule: true
}
这里要注意:electron12版本以后,默认是移除了remote的,官方推荐路由的方式来处理。如果想了解的建议直接去官网。这里我们还是选择用remote,既然官网移除了,那么我们再把它安装回来。
npm install @electron/remote --save
问题:
此时再次点击新建窗口,发现还是不能,这是为什么呢?
我们console.log("随便")随便打印点东西看看能否出现结果。结果无法展示出来,说明点击就没起作用。
而我们检查了语法又没有问题。
这是因为我们把整个菜单栏全部都设置成了拖拽功能了,所以才导致无法点击。
解决办法就是将li标签列表设置为不可拖拽。
6.4.2 小总结
总结使用无边框的菜单栏使用步骤:
1. main.js的主窗口中关闭frame。
2. 在对应渲染页面中编写菜单的html结构,并自己设置对应的css样式。
3. 记得在css样式合适的位置设置-webkit-app-region: drag;让其可拖拽,为保障菜单功能点击有效,记得在对应的名称上设置禁止拖拽-webkit-app-region: no-drag;否则父标签的拖拽效果会传递给子标签。
4. 给菜单添加点击事件。
5. 如果要让点击后弹窗,需要使用到Main进程的BrowserWindow。则需要remote出来。
6. 因此需要在主进程开启remote模块。
7. 同时要在js中使用nodejs的东西,则也需要开启node模块。
6.4.2 点击打开网页
同样的道理,我们再来试一试点击打开一个网页。
为了照顾到不同版本带来的remote差异,我们直接用原生的菜单栏。然后把原来自己写的自定义菜单栏html代码注释掉,免得影响美观。
七、打开对话框读取文件
为了照顾到不同版本带来的remote差异,我们直接用原生的菜单栏。然后把原来自己写的自定义菜单栏html代码注释掉,免得影响美观。接着给菜单栏增加一个子菜单:导入文件。
// 导入electron对象
// app 控制应用程序的事件生命周期。
// BrowserWindow 创建并控制浏览器窗口。
// Menu 创建原生应用菜单和上下文菜单。
const { app,BrowserWindow} = require('electron')
// 开启热加载
const reloader = require('electron-reloader')
reloader(module)
// 控制ready事件
// ready事件是:当 Electron 完成初始化时,发出一次。
app.on('ready',()=>{
// 新建窗口
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
// 是否显示原生菜单栏
frame: true,
webPreferences: {
// 开启node模块
nodeIntegration: true,
// 开启remote模块
enableRemoteMoudle: true
}
});
// 让主窗口加载文件 html文件
mainWindow.loadFile('./src/index.html');
// 引入自定义菜单
require('./menu')
// 自动打开调试窗口
mainWindow.webContents.openDevTools();
})
引入dialog并展示,此时就弹出了对话框
下面我们看看可以填写哪些参数:dialog | Electron
由于时间有限,暂时整理到这里,如果有迫切的需要,请联系我,我会以你意想不到的速度进行补充。O(∩_∩)O