electron

1.创建工程

1
npm init

然后疯狂敲键盘回车

修改配置, 注意author和description是必填项
还有就是需要再scripts中添加启动脚本

1
2
3
4
5
6
7
8
9
10
11
{
"name": "electron-test",
"version": "1.0.0",
"description": "this is a simple electron demo",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"author": "肉豆蔻吖",
"license": "ISC"
}
1
2
npm install --save-dev electron

根目录下创建main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
console.log('hello electron');

// console.log('hello electron');

const { app, BrowserWindow } = require('electron');

app.on('ready', () => {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
// x: 0,
// y: 0,
// alwaysOnTop: true
})
win.loadURL('http://xiamu.icu/')
})

效果如下:

2.本地静态资源

创建pages/index.html
pages/index.css

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
<!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>
<link rel="stylesheet" href="./index.css">
</head>
<body>
<h1>欢迎学习Electron开发</h1>
</body>
</html>

index.css

1
2
3
4
h1 {
background-color: gray;
color: orange;
}

修改main.js, 使用win.loadFile(‘./pages/index.html’)函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// console.log('hello electron');

const { app, BrowserWindow } = require('electron');

app.on('ready', () => {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
// x: 0,
// y: 0,
// alwaysOnTop: true
})
// win.loadURL('http://xiamu.icu/')
win.loadFile('./pages/index.html')
})

然后npm start, 启动

按下快捷键Ctrl Shift I可以打开熟悉的浏览器控制台

打开控制台之后, 有个一个警告, 这个警告可以直接忽略, Request Autofill.enable failed

但是浏览器的控制台有一个警告, 这个警告不能忽略

在网页中添加

1
2
3
  <meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';" />

按下Ctrl r进行刷新, Electron应用控制台就没有警告了

参考: https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CSP
https://www.electronjs.org/zh/docs/latest/tutorial/quick-start

完善窗口行为

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// console.log('hello electron');

const { app, BrowserWindow } = require('electron');

function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
// x: 0,
// y: 0,
// alwaysOnTop: true
})
// win.loadURL('http://xiamu.icu/')
win.loadFile('./pages/index.html')
}

app.on('ready', () => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})


配置自动重启(热部署)

安装Nodemon

1
npm i nodemon -D

package.json启动脚本命令修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"name": "electron-test",
"version": "1.0.0",
"description": "this is a simple electron demo",
"main": "main.js",
"scripts": {
"start": "nodemon --exec electron ."
},
"author": "肉豆蔻吖",
"license": "ISC",
"devDependencies": {
"electron": "^31.0.2"
}
}

根目录下创建nodemon.json

1
2
3
4
5
6
7
8
9
{
"ignore": [
"node_modules",
"dist"
],
"restartable": "r",
"watch": ["*.*"],
"ext": "html,js,css"
}

重启 npm start

每当保存的时候,页面就会自动刷新了,或者在vscode的控制台上手动扣一下r

主进程和渲染进程

主进程就是main.js
渲染进程是render.js

main.js相当于是vscode的控制台,render.js相当于是浏览器的控制台

pages/render.js

1
2
3
4
5
const btn1 = document.getElementById('btn1')

btn1.onclick = () => {
alert('你好啊!')
}

然后修改index.html代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!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>
<link rel="stylesheet" href="./index.css">
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';" />
</head>
<body>
<h1>欢迎学习Electron开发!!</h1>
<button id="btn1">点我</button>
<script type="text/javascript" src="./render.js"></script>
</body>
</html>

主进程和渲染进程,这两者想要进行通信,就得借助一个预加载脚本

preload脚本

根目录创建preload.js

main.js与preload建立联系

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// console.log('hello electron');

const { app, BrowserWindow } = require('electron');
const path = require('path')

function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, './preload.js')
}
// x: 0,
// y: 0,
// alwaysOnTop: true
})
// win.loadURL('http://xiamu.icu/')
win.loadFile('./pages/index.html')
}

app.on('ready', () => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})


preload.js

1
2
3
4
5
6
7
console.log('preload');

const { contextBridge } = require('electron');

contextBridge.exposeInMainWorld('myAPI', {
version: process.version
})

render.js

1
2
3
4
5
6
const btn1 = document.getElementById('btn1')

btn1.onclick = () => {
console.log(window);
alert(myAPI.version)
}

最终页面效果,渲染进程成功获取到了主进程的版本号了

预加载脚本只能使用部分的主进程的函数,比如process, 不能够使用 __dirname

进程通信(IPC)

1.渲染进程 => 主进程(单向)

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<!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>
<link rel="stylesheet" href="./index.css">
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';" />
</head>
<body>
<h1>欢迎学习Electron开发!!</h1>
<button id="btn1">点我</button>
<br>
<br>
<hr>
<input id="input" type="text">
<button id="btn2">向D盘写点东西</button>
<script type="text/javascript" src="./render.js"></script>
</body>
</html>

render.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
console.log('render');

const btn1 = document.getElementById('btn1')
const btn2 = document.getElementById('btn2')
const input = document.getElementById('input')

btn1.onclick = () => {
console.log(window);
alert(myAPI.version)
}

btn2.onclick = () => {
myAPI.saveFile(input.value)
}

preload.js

1
2
3
4
5
6
7
8
9
10
console.log('preload');

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('myAPI', {
version: process.version,
saveFile: (data) => {
ipcRenderer.send('file-save', data)
}
})

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
// console.log('hello electron');

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path')
const fs = require('fs');

function writeFile(_, data) {
fs.writeFileSync('D:/hello.txt', data)
}

function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, './preload.js')
}
// x: 0,
// y: 0,
// alwaysOnTop: true
})
ipcMain.on('file-save', writeFile)
// win.loadURL('http://xiamu.icu/')
win.loadFile('./pages/index.html')
}

app.on('ready', () => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})


2.渲染进程 <=> 主进程(双向)

index.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!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>
<link rel="stylesheet" href="./index.css">
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; img-src https://*; child-src 'none';" />
</head>
<body>
<h1>欢迎学习Electron开发!!</h1>
<button id="btn1">点我</button>
<br>
<br>
<hr>
<input id="input" type="text">
<button id="btn2">向D盘写点东西hello.txt</button>
<br>
<br>
<hr>
<button id="btn3">读取D盘中的hello.txt</button>
<script type="text/javascript" src="./render.js"></script>
</body>
</html>

main.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// console.log('hello electron');

const { app, BrowserWindow, ipcMain } = require('electron');
const path = require('path')
const fs = require('fs');

function writeFile(_, data) {
fs.writeFileSync('D:/hello.txt', data)
}

function readFile() {
return fs.readFileSync('D:/hello.txt').toString()
}

function createWindow() {
const win = new BrowserWindow({
width: 800,
height: 600,
autoHideMenuBar: true,
webPreferences: {
preload: path.resolve(__dirname, './preload.js')
}
// x: 0,
// y: 0,
// alwaysOnTop: true
})
ipcMain.on('file-save', writeFile)
ipcMain.handle('file-read', readFile)
// win.loadURL('http://xiamu.icu/')
win.loadFile('./pages/index.html')
}

app.on('ready', () => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})

app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})


preload.js

1
2
3
4
5
6
7
8
9
10
11
12
13
console.log('preload');

const { contextBridge, ipcRenderer } = require('electron');

contextBridge.exposeInMainWorld('myAPI', {
version: process.version,
saveFile: (data) => {
ipcRenderer.send('file-save', data)
},
readFile() {
return ipcRenderer.invoke('file-read')
}
})

render.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
console.log('render');

const btn1 = document.getElementById('btn1')
const btn2 = document.getElementById('btn2')
const btn3 = document.getElementById('btn3')
const input = document.getElementById('input')

btn1.onclick = () => {
console.log(window);
alert(myAPI.version)
}

btn2.onclick = () => {
myAPI.saveFile(input.value)
}

btn3.onclick = async () => {
let data = await myAPI.readFile()
alert(data)
}

运行效果:

打包

安装打包工具

1
npm install electron-builder -D

添加配置
package.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
{
"name": "electron-test",
"version": "1.0.0",
"description": "this is a simple electron demo",
"main": "main.js",
"scripts": {
"start": "nodemon --exec electron .",
"build": "electron-builder"
},
"build": {
"appId": "icu.xiamu.video",
"win": {
"icon": "./logo.ico",
"target": [
{
"target": "nsis",
"arch": [
"x64"
]
}
]
},
"nsis": {
"oneClick": false,
"perMachine": true,
"allowToChangeInstallationDirectory": true
}
},
"author": "肉豆蔻吖",
"license": "ISC",
"devDependencies": {
"electron": "^31.0.2",
"electron-builder": "^24.13.3",
"nodemon": "^3.1.4"
}
}

根目录准备一个logo.ico

然后进行打包

1
npm run build

electron-vite

https://electron-vite.org/


electron
https://xiamu.icu/Web/electron/
作者
肉豆蔻吖
发布于
2024年6月24日
许可协议