赞
踩
最近时间比较富裕 咱们浅浅来学习下electron
视频在这禹神:一小时快速上手Electron,前端Electron开发教程_哔哩哔哩_bilibili
先看下流程模型
首先第一步 查看你的node和npm版本
创建一个文件夹 我创建的名称为my-electron-app
然后打开vscode
npm init
交互式 init
命令将提示你在配置中设置一些字段。出于本教程的目的,需要遵循一些规则:
entry point
应该是 main.js
。
author(名字创建者)
和 description(描述)
可以是任何值,但对于 应用打包 是必需的。
你的 package.json
文件应如下所示:
- {
- "name": "my-electron-app",
- "version": "1.0.0",
- "description": "Hello World!",
- "main": "index.js",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1"
- },
- "author": "zhou",
- "license": "ISC"
- }
划重点!!!!必填必填!!!打包要用到!!
然后,将 electron
包安装到应用的 devDependencies
中。
npm install --save-dev electron
最后,你希望能够执行 Electron。在 package.json
配置的 scripts 字段中,添加 start
命令,如下所示:
- {
- "scripts": {
- "start": "electron ."
- }
- }
此 start
命令将允许你在开发模式下打开应用。
npm start
注意:该脚本告诉 Electron 在项目的根文件夹上运行。在此阶段,你的应用将立即抛出错误,告诉你它找不到要运行的应用。如下:
这是什么意思呢就是main是一个主入口 而现在没有这个主入口 它找不到 所以就报错了 那怎么解决这个问题呢 也很好解决 加上就是了吗(package.json里边别忘记修改哦)
在项目的根文件夹中创建pages文件夹在下边创建 index.html和index.css
文件:
- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <!-- https://web.nodejs.cn/en-US/docs/Web/HTTP/CSP -->
- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
- <title>Hello World!</title>
- <link rel="stylesheet" href="./index.css">
- </head>
-
- <body>
- <h1>欢迎学习Electron开发!!!</h1>
- </body>
-
- </html>
现在你已经有了一个网页,将其加载到应用窗口中。为此,你需要两个 Electron 模块:
app 模块,控制应用的事件生命周期。
BrowserWindow 模块,用于创建和管理应用窗口。
由于主进程运行 Node.js,因此你可以将它们作为 CommonJS 模块导入到 main.js
文件的顶部:
const { app, BrowserWindow } = require('electron')
然后,添加一个 createWindow()
函数,将 index.html
加载到新的 BrowserWindow
实例中。
- const createWindow = () => {
- const win = new BrowserWindow({
- width: 800,
- height: 600,
- });
-
- win.loadFile("./pages/index.html");
- };
接下来,调用此 createWindow()
函数来打开窗口。
在 Electron 中,浏览器窗口只能在 app
模块的 ready 事件被触发后创建。你可以使用 app.whenReady() API 等待此事件。在 whenReady()
解决其 Promise 后调用 createWindow()
。或者是app.on("ready")来 此处我喜欢用后者 因为他俩是一样的 用哪个无所谓哈
- const { app, BrowserWindow } = require("electron");
- const createWindow = () => {
- const win = new BrowserWindow({
- width: 800,
- height: 600,
- });
-
- win.loadFile("./pages/index.html");
- };
- // app.whenReady().then(() => {
- // createWindow();
-
- // });
- app.on("ready", () => {
- createWindow();
- });
然后运行一下npm start
一个桌面应用就出现了
尽管你现在可以打开浏览器窗口,但你将需要一些额外的样板代码,以使其感觉对每个平台更加原生。应用窗口在每个操作系统上的行为都不同,Electron 让开发者有责任在他们的应用中实现这些约定。
一般来说,你可以使用 process
全局的 platform 属性来运行专门针对某些操作系统的代码。
在 Windows 和 Linux 上,退出所有窗口通常会完全退出应用。
要实现此目的,请监听 app
模块的 'window-all-closed' 事件,如果用户不在 macOS (darwin
) 上,则调用 app.quit()。
- app.on('window-all-closed', () => {
- if (process.platform !== 'darwin') app.quit()
- })
Linux 和 Windows 应用在没有打开任何窗口时退出,而 macOS 应用通常即使没有打开任何窗口也会继续运行,并且在没有可用窗口时激活应用应该打开一个新窗口。
要实现此功能,请监听 app
模块的 activate 事件,如果没有打开浏览器窗口,则调用现有的 createWindow()
方法。
由于无法在 ready
事件之前创建窗口,因此你应该仅在应用初始化后监听 activate
事件。通过从现有 whenReady()
回调中附加事件监听器来执行此操作。
- app.on("ready", () => {
- createWindow();
- app.on("activate", () => {
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
- });
- });
如果你不想要上边那些个小标题 就加个属性 autoHideMenuBar:true
效果是这样的
看好进程 有主进程和渲染进程 我们还没看见渲染进程 不怕 我们在pages里写一个render.js,那怎么引入js呢 就很简单呀在html直接引入就好了
render.js与index。html的交互
- const btn1 = document.getElementById("btn1");
- btn1.onclick = () => {
- alert("你点我了");
- };
点击效果图如下
就比如我想要alert弹窗的时候我想要拿到node的版本怎么拿呢
在主进程我是可以拿到的
但是渲染进程就不行 控制器怎么调出来的ctrl+shift+i
为啥会报错 因为render.js是渲染环境 他没法拿到node的process方法 那怎么办
现在,最后要做的是将 Electron 的版本号及其依赖打印到你的网页上。
在主进程中通过 Node 的全局 process
对象访问此信息很简单。但是,你不能只从主进程编辑 DOM,因为它无法访问渲染器的 document
上下文。他们处于完全不同的进程!
这时将预加载脚本附加到渲染器就派上用场了。预加载脚本在加载渲染器进程之前运行,并且可以访问渲染器全局变量(例如 window
和 document
)和 Node.js 环境。
需要个预加载脚本通信 在根目录下新建个preload.js文件
使preload能进行打印 main.js需要加上这段代码
- webPreferences: {
- preload: path.resolve(__dirname, "./preload.js"),
- },
然后npm start运行下
就能看到是preload先执行 然后执行的render
那我现在想要在渲染进程里边打印process 我就得通过perload(它虽然是运行在渲染进程的,但是它可以使用部分node语法 就比如process)尝试下
打印出来了
那么 预加载文件如何把process传给渲染进程render.js呢
需要个属性
- const { contextBridge } = require("electron");
- contextBridge.exposeInMainWorld("abc", {
- xyz: 100,
- });
先看这是没有写
// contextBridge.exposeInMainWorld("abc", {
// xyz: 100,
// });
注释掉了 所以不执行 我们在控制台打印window 可见里边没有这个属性
那我把注释打开看下 可见能在window里拿到这个abc了
同理 如果我要是想拿process的话
概述:在渲染进程中 ipcRenderer.send发送消息 ,在主进程中使用ipcMain.on接收消息
常用于 在web中使用主进程的API,例如下边这个需求
点击按钮 在用户的D盘创建一个hello.text文件 文件内容来自于用户输入
看下效果:
是可以拿到输入的值的 那么怎么传给主进程呢 敲重点!!!
预加载脚本引入ipcRenderer .send使用
- console.log("preload", process.version);
- const { contextBridge,ipcRenderer } = require("electron");
- contextBridge.exposeInMainWorld("myAPI", {
- process: process.version,
- saveFile:(data)=>{
- ipcRenderer.send('file-save',data)
- }
- });
渲染进程点击按钮传值
- const btn1 = document.getElementById("btn1");
- const btn2 = document.getElementById("btn2");
- const input = document.getElementById("input");
- console.log("render");
-
- btn1.onclick = () => {
- alert(window.myAPI.process);
- };
-
-
- btn2.onclick = () => {
- myAPI.saveFile(input.value)
- };
主进程使用 ipcMain.on接收
- const { app, BrowserWindow,ipcMain } = require("electron");
- const path = require("path");
- const fs=require('fs')
-
- function writeFile(event,data){
- fs.writeFileSync('D://hello.text',data)
-
- }
- const createWindow = () => {
- const win = new BrowserWindow({
- width: 800,
- height: 600,
- autoHideMenuBar: true,
- webPreferences: {
- preload: path.resolve(__dirname, "./preload.js"),
- },
- });
- ipcMain.on("file-save",writeFile);
-
- win.loadFile("./pages/index.html");
- };
- // app.whenReady().then(() => {
- // createWindow();
-
- // });
- app.on("ready", () => {
- createWindow();
- app.on("activate", () => {
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
- });
- });
-
- app.on("window-all-closed", () => {
- if (process.platform !== "darwin") app.quit();
- });
画一下重点
然后运行下npm start
总结下 就是在preload里边使用ipcRenderer.send方法然后render里边点击按钮调用这个方法然后在主进程里边使用 ipcMain.on进行接收 然后进行操作
例子:读取D盘里边hello.text
预加载里边写一个方法readFile 用invoke
- console.log("preload", process.version);
- const { contextBridge, ipcRenderer } = require("electron");
- contextBridge.exposeInMainWorld("myAPI", {
- process: process.version,
- saveFile: (data) => {
- ipcRenderer.send("file-save", data);
- },
- readFile: () => {
- return ipcRenderer.invoke("file-read");
- },
- });
然后html里边写个按钮 读取hello.text
- <!DOCTYPE html>
- <html lang="en">
-
- <head>
- <meta charset="UTF-8">
- <!-- https://web.nodejs.cn/en-US/docs/Web/HTTP/CSP -->
- <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
- <title>Hello World!</title>
- <link rel="stylesheet" href="./index.css">
- </head>
-
- <body>
-
- <button id="btn3" >读取D盘中的hello.text</button>
-
-
- <script src="./render.js"></script>
- </body>
-
- </html>
render.js里编写 调用预加载脚本的方法
-
- const btn3 = document.getElementById("btn3");
-
-
-
- btn3.onclick =() => {
- myAPI.readFile();
- };
-
然后主进程使用 ipcMain.handle进行接收
- const { app, BrowserWindow, ipcMain } = require("electron");
- const path = require("path");
- const fs = require("fs");
-
- function writeFile(event, data) {
- fs.writeFileSync("D://hello.text", data);
- }
- // readFile;
- function readFile() {
- let res = fs.readFileSync("D://hello.text").toLocaleString();
- console.log(res, "res");
- return res
- }
- const createWindow = () => {
- const win = new BrowserWindow({
- width: 800,
- height: 600,
- autoHideMenuBar: true,
- webPreferences: {
- preload: path.resolve(__dirname, "./preload.js"),
- },
- });
- ipcMain.on("file-save", writeFile);
- ipcMain.handle("file-read", readFile);
-
- win.loadFile("./pages/index.html");
- };
- // app.whenReady().then(() => {
- // createWindow();
-
- // });
- app.on("ready", () => {
- createWindow();
- app.on("activate", () => {
- if (BrowserWindow.getAllWindows().length === 0) createWindow();
- });
- });
-
- app.on("window-all-closed", () => {
- if (process.platform !== "darwin") app.quit();
- });
划重点
读取完毕之后 需要返回给预加载脚本 用return 预加载脚本也直接return 然后就是render里边进行接收
因为是异步 所以接收到的是个pending状态 我们用await来接收下
就可以拿到了 总结下 就是在preload里边使用ipcRenderer.invoke方法然后render里边点击按钮调用这个方法然后在主进程里边使用 ipcMain.handle进行接收 接收完之后要使用render给他return出去 在预加载脚本里边也要return出去 然后在render.js里边使用async和await进行接收就行了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。