2023 最新前端 Electron Gui 实现桌面应用开发详细教程(基础篇)

Electron 基本概述

Electron 是利用 web 前端技术进行桌面应用开发的一套框架,它是由 Github 开发的,利用HTML、CSS、JavaScript 来构建跨平台桌面应用程序的一个开源库。Electron 通过将 Chromium 和 Node.js 合并到同一个运行时环境中,并将其打包成 Mac、Windowns、Linux 系统下的应用来实现这一目的。

Electron 官方网站:https://www.electronjs.org/

在这里插入图片描述
chrome 和 chromium 用户界面几乎一摸一样,但是还是有一些差异的。比如 chrome 的系统标题和边框是被默认禁用的,而 chromium 是默认开启的。另外chrome地址栏里有分享功能,我们可以分享网站,但是 chromium 没有这个功能。

界面的细微差别主要是这两个浏览器面向的用户是不一样的,一般来说使用 chrome 的用户是普通用户,用它来浏览网页使用,而使用 chromium 大部分是极客、开发人员和体验新功能的的用户。

1. Chromium:支持最新特性的浏览器。
2. Node.js:javascript运行时,可实现文件读写等。
3. Native APls:提供统一的原生界面能力。

主进程 Main Process & 渲染进程 Renderer Process & IPC 通信机制

在这里插入图片描述
渲染进程无法调用 计算机系统资源,只能由主进程去调用系统资源。

在这里插入图片描述

Main Process 主进程:一个应用只会有一个主进程,只有主进程才能进行 GUI 的 API 操作。

Renderer Process 渲染进程:一个应用可以有一个主进程,渲染进程才是 GUI 的表现。

Electron 环境安装

验证 node 是否安装成功

在 cmd 窗口:node -v 如果出现版本号表示安装成功。

C:\Users\HP>node -v
v16.10.0

在 cmd 窗口:npm -v 查看 npm 的版本

C:\Users\HP>npm -v
7.24.0

安装 cnpm 采用淘宝镜像安装 electron

npm install cnpm -g  --registry=https://registry.npm.taobao.org

cnpm : 无法加载文件 E:\Environment\NodeJs-16.10.0\node_global\cnpm.ps1,因为在此系统上禁止运行脚本。有关详细信息,请参阅 https:/go.microsoft.com/fwlink/?LinkID=13 5170 中的 about_Execution_Policies。

解决方案:打开 PowerShell 管理员模式

PS C:\Windows\system32> set-ExecutionPolicy RemoteSigned

在 cmd 命令窗口:cnpm -v 查看版本信息

PS C:\Users\HP\Desktop\JS-EXE> cnpm -v
cnpm@9.0.1 (E:\Environment\NodeJs-16.10.0\node_global\node_modules\cnpm\lib\parse_argv.js)
npm@8.19.4 (E:\Environment\NodeJs-16.10.0\node_global\node_modules\cnpm\node_modules\npm\index.js)
node@16.10.0 (E:\Environment\NodeJs-16.10.0\node.exe)
npminstall@7.5.1 (E:\Environment\NodeJs-16.10.0\node_global\node_modules\cnpm\node_modules\npminstall\lib\index.js)
prefix=E:\Environment\NodeJs-16.10.0\node_global
win32 x64 10.0.19044
registry=https://registry.npmmirror.com

安装 electron,全局安装

打开cmd窗口,在命令窗口输入命令下载安装:

cnpm install electron -g

当然可以直接 npm 下载

npm install electron -g
All packages installed (70 packages installed from npm registry, used 42s(network 29s), speed 68.43KB/s, json 68(765.94KB), tarball 1.2MB, manifests cache hit 0, etag hit 0 / miss 0)
[electron@23.1.1] link E:\Environment\NodeJs-16.10.0\node_global\electron@ -> E:\Environment\NodeJs-16.10.0\node_global\node_modules\electron\cli.js

在cmd命令窗口中输入命令:electron -v 查看版本信息

PS C:\Users\HP\Desktop\JS-EXE> electron -v

v23.1.1

启动 electron 快捷会话窗

PS C:\Users\HP\Desktop\JS-EXE> electron -version

在这里插入图片描述

环境安装异常

登录淘宝 NPM 镜像网站(https://npm.taobao.org/)进入 electron 镜像

选择你计算机操作系统相应的版本:Window 系统 x64 版本 安装

解压完成

下载完毕,解压压缩包,进入demo项目的 node_modules > electron 文件夹,创建 dist 文件夹,将下载的 zip 包里的文件复制到 dist 文件夹下,注意目录结构

在这里插入图片描述

推荐配置环境变量

在这里插入图片描述

测试结果:

PS C:\Users\HP\Desktop\唤醒手腕\electron-2023-03-02> electron -v
PS C:\Users\HP\Desktop\唤醒手腕\electron-2023-03-02> 
v23.1.1

让 electron 全局读取到包:把 electron文件夹 放到 node_global/node_modules 目录下

在这里插入图片描述
require 找包流程

当主程序执行到 const { app, BrowserWindow } = require(‘electron’) 这句的时候,会首先在主程序 main.js 同级目录下查找 node_modules 目录。
然后在 node_modules 目录下查找 electron 包目录。
然后在 electron 包目录下的 package.json 文件中找到 main 属性,main 属性的值就是要加载的文件。
“main”:./lib/xxx.js”
如果 electron 包目录下没有 package.json 文件,或者 package.json 文件中没有 main 属性,则会默认加载electron 包目录下的 index.js 文件。
如果以上方式没有找到,然后会去全局查找 node_global/node_modules 文件夹。

安装 Snippets 插件

A collection of handy ElectronJS snippets.

在这里插入图片描述

创建 Hello World

初始化 npm 项目

Electron 应用基于 npm 搭建,以 package.json 文件作为入口点。 首先创建一个文件夹,然后在其中执行 npm init 初始化项目。

mkdir my-electron-app && cd my-electron-app
npm init

这条命令会帮您配置 package.json 中的一些字段。然后将 Electron 安装为您项目的 devDependencies,即仅在开发环境需要的额外依赖。

package.json:入口点 应当是 main.js (您很快就会创建它) author (作者)、license (开源许可证) 和 description (描述) 可以为任意内容,不过在晚些的 打包应用程序 步骤中可能是需要的。

为什么 ELECTRON 是 DEVDEPENDENCY?

您的应用需要运行 Electron API,因此这听上去可能有点反直觉。 实际上,打包后的应用本身会包含 Electron
的二进制文件,因此不需要将 Electron 作为生产环境依赖。

安装 electron

npm install electron --save-dev

在初始化并且安装完 Electron 之后,您的 package.json 应该长下面这样。 文件夹中会出现一个 node_modules 文件夹,其中包含了 Electron 可执行文件;还有一个 package-lock.json 文件,指定了各个依赖的确切版本。

package.json

{
	"name": "my-electron-app",
	"version": "1.0.0",
	"description": "Hello World!",
	"main": "main.js",
	"author": "Jane Doe",
	"license": "MIT",
	"devDependencies": {
	  	"electron": "19.0.0"
	}
}

添加 .gitignore 文件

.gitignore 指定了哪些文件不需要 Git 追踪版本。 建议您复制一份 GitHub 的 Node.js gitignore 模板 到您项目的根目录,以避免将 node_modules 文件夹提交到版本控制系统中。

运行 Electron 应用

您在 package.json 中指定的脚本文件 main 是所有 Electron 应用的入口点。 这个文件控制 主程序 (main process),它运行在 Node.js 环境里,负责控制您应用的生命周期、显示原生界面、执行特殊操作并管理渲染器进程 (renderer processes)

因为 Electron 的主进程是一个 Node.js 运行时,您可以使用 electron 命令执行任意 Node.js 代码(甚至将其用作 REPL)。 要执行这个脚本,在 package.json 的 scripts 字段中添加一个 start 命令,执行内容为 electron . 。 这个命令会告诉 Electron 在当前目录下寻找主脚本,并以开发模式运行它。

{
	"name": "my-electron-app",
	"version": "1.0.0",
	"description": "Hello World!",
	"main": "main.js",
	"author": "Jane Doe",
	"license": "MIT",
	"scripts": {
	  	"start": "electron ."
	},
	"devDependencies": {
	  	"electron": "^19.0.0"
	}
}
npm run start

将网页装载到 BrowserWindow

在 Electron 中,每个窗口展示一个页面,后者可以来自本地的 HTML,也可以来自远程 URL。 在本例中,您将会装载本地的文件。 在您项目的根目录中创建一个 index.html 文件,并写入下面的内容:

<!DOCTYPE html>
<html>
	<head>
		<meta charset="UTF-8" />
		<title>Hello from Electron renderer!</title>
	</head>
	<body>
		<h1>Hello from Electron renderer!</h1>
		<p>👋</p>
	</body>
</html>

现在您有了一个网页,可以将它装载到 Electron 的 BrowserWindow 上了。 将 main.js 中的内容替换成下列代码。

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

const createWindow = () => {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
    })

    win.loadFile('index.html')
}

app.whenReady().then(() => {
    createWindow()
})

app,它控制您的应用的事件生命周期。

BrowserWindow,它负责创建和管理应用的窗口。

将可复用的函数写到实例化窗口

createWindow() 函数将您的页面加载到新的 BrowserWindow 实例中:

const createWindow = () => {
	const win = new BrowserWindow({
		width: 800,
		height: 600,
	})
	
	win.loadFile('index.html')
}

在应用准备就绪时调用函数

Electron 的很多核心模组是 Node.js 事件触发器,遵守 Node.js 的异步事件驱动架构。 app 模块就是其中一个。

在 Electron 中,只有在 app 模组的 ready 事件能触发后才能创建 BrowserWindows 实例。 您可以借助 app.whenReady() API 来等待此事件,并在该 API 的 promise 被 resolve 时调用 createWindow() 方法。

通常我们使用触发器的 .on 函数来监听 Node.js 事件。

+ app.on('ready').then(() => {
- app.whenReady().then(() => {
  	createWindow()
})

但是 Electron 暴露了 app.whenReady() 方法,作为其 ready 事件的专用监听器,这样可以避免直接监听 .on 事件带来的一些问题。

关闭所有窗口时退出应用 (Windows & Linux)

在 Windows 和 Linux 上,我们通常希望在关闭一个应用的所有窗口后让它退出。 若要在 Electron 中实现这一点,您可以监听 window-all-closed 事件,并调用 app.quit() 来让应用退出。这不适用于 macOS。

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

Electron 程序是通过 npm 包创建的。 您应将 Electron 依赖安装到 devDependencies ,然后在 package.json 中设置一个脚本来运行。

执行命令后,Electron 程序会运行您在 package.json 文件的 main 字段设置的入口文件。 这个入口文件控制着 Electron 的主进程,后者运行于 Node.js 实例,负责应用的生命周期、展示原生窗口、执行特殊操作和管理渲染进程。

渲染器进程(简称渲染器) 负责展示图形内容。 您可以将渲染的网页指向 web 地址或本地 HTML 文件。 渲染器和常规的网页行为很相似,访问的 web API 也相同。

窗口 html 页面加载

加载远程URL:

win.loadURL('https://github.com')

加载本地HTML文件:

win.loadURL(`file://${__dirname}/app/index.html`)

基础案例测试

在根目录下新建一个 app.js 文件,并填写如下代码,这个就是 Electron 的主进程文件

let electron = require('electron');

let app = electron.app;

let BrowserWindow = electron.BrowserWindow;
let mainWindow = null;

app.on('ready', () => {
    mainWindow = new BrowserWindow({width: 300, height: 200})
    mainWindow.loadFile("helloworld.html")
    mainWindow.on('colsed', () => {
        mainWindow = null
    })
})

构建前端页面

<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>helloworld</h1>
</body>
</html>

在终端位置直接使用命令:npm init --yes 来初始化 package.json 文件

{
  "name": "js-exe",
  "version": "1.0.0",
  "main": "app.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}

运行项目,在终端位置输入命令:electron . (注意命令最后带 .) 运行结果:
在这里插入图片描述

app 常见事件监听

(1)、ready 当 electron 完成初始化时被触发

app.on('ready', () => {
  	createWindow();
})

(2)、window-all-closed 所有窗口被关闭

app.on('window-all-closed', function () {
	console.log("window-all-closed")
})

(3)、quit 在所有应用程序退出时发出

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

(4)、open-file 在应用中要打开一个文件时发出

app.on('open-file', function () {
  	console.log("open-file")
})

(5)、open-url 应用中要打开一个 URL 网址时发出

app.on('open-url', function () {
  	console.log("open-url")
})

(6)、activate 当应用被激活时发出

app.on('activate', function () {
  	console.log("activate")
})

窗口生命周期

ready: app 初始化完成
dom-ready: 一个窗口中的文本加载完成
did-finish-load: 导航完成时触发
closed: 当窗口关闭时触发,此时应删除窗口引用
window-all-closed: 所有窗口都被关闭时触发
before-quit: 在关闭窗口之前触发
will-quit: 在窗口关闭并且应用退出时触发
quit: 当所有窗口被关闭时触发

生命周期案例测试

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

const createWindow = () => {
    const win = new BrowserWindow({
        width: 800,
        height: 600,
    })

    win.loadFile("index.html")

    win.webContents.on("dom-ready" , ()=> {
        console.log("dom ready")
    })

    win.webContents.on("did-finish-load", ()=> {
        console.log("did finish load")
    })

    win.on('closed', ()=> {
        console.log("closed")
    })
}

app.whenReady().then(() => {
    console.log("ready finish")
    createWindow()
})

app.on("window-all-closed", () => {
    console.log("all window close")
    app.quit()
})

app.on("before-quit", () => {
    console.log("before quit")
})

app.on("will-quit", () => {
    console.log("will quit")
})

app.on("quit", () => {
    console.log("quit")
})

案例运行结果

ready finish
dom ready
did finish load
closed
all window close
before quit     
will quit       
quit

特别注意:如果指定了 window-all-closed 就是重写了系统监听(系统自动执行监听)的,需要手动执行 quit()。

webContents 常用事件

did-finish-load 导航完成时触发,即选项卡的旋转器将停止旋转,并指派 onload 事件后

mainWindow.webContents.on('did-finish-load',()=>{
	console.log("did-finish-load")
})

dom-ready 一个框架中的文本加载完成后触发该事件

mainWindow.webContents.on('dom-ready',()=>{
	console.log("dom-ready")
})

npm 常见异常问题

Error: Cannot find module ‘bug-versions/package.json’

自动装配 package.json,然后自动安装所需的依赖

npm install --save-dev
cnpm install --save-dev

ERROR Error: Cannot find module ‘webpack’

cnpm install webpack --save-dev

ERROR Error: Cannot find module ‘@vue/babel-preset-app’

npm install @vue/babel-preset-app -dev

npm ERR! Maximum call stack size exceeded  rm -rf node_modules package-lock.json

npm install

npm 查看当前源

npm get registry

npm 切换成淘宝镜像

npm config set registry http://registry.npm.taobao.org/

npm 设置官方源

npm config set registry http://www.npmjs.org

在较慢的网络上, 最好使用 --verbose 标志来显示下载进度:

npm install --verbose electron

窗口初始化调整

Class :BrowserWindow:Create and control browser windows.

Process: Main:This module cannot be used until the ready event of the app module is emitted.

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
win.loadURL('https://github.com')
win.loadFile('index.html')

While loading the page, the ready-to-show event will be emitted when the renderer process has rendered the page for the first time if the window has not been shown yet. Showing the window after this event will have no visual flash:

const { BrowserWindow } = require('electron')
const win = new BrowserWindow({ show: false })
win.once('ready-to-show', () => {
	win.show()
})

This event is usually emitted after the did-finish-load event, but for pages with many remote resources, it may be emitted before the did-finish-load event.

Please note that using this event implies that the renderer will be considered “visible” and paint even though show is false. This event will never fire if you use paintWhenInitiallyHidden: false

new BrowserWindow 案例

const win = new BrowserWindow({
    x: 200,
    y: 200,
    frame: false,
    autoHideMenuBar: true,
    show: false,
    width: 800,
    height: 600,
    icon: './icon.ico',
    title: "hello world",
    maxWidth: 1000,
    maxHeight: 800,
    minWidth: 400,
    minHeight: 300,
    resizable: false,
})

win.loadFile("index.html")

win.on('ready-to-show', () => {
    win.show()
})

隐藏窗口 恢复窗口

使用BrowserWindow对象的hide方法来隐藏窗口

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

let mainWindow;

app.whenReady().then(() => {
    mainWindow = new BrowserWindow({
        width: 800, height: 600,
    });

    mainWindow.on('closed', () => {
        app.quit();
    });

    mainWindow.hide();
});

恢复窗口

mainWindow.show();

获取窗口屏幕位置

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

app.whenReady().then(() => {
    const mainWindow = new BrowserWindow({
        width: 800, height: 600,
    });

    const windowPosition = mainWindow.getPosition();
    const windowX = windowPosition[0];
    const windowY = windowPosition[1];

    console.log('窗口横坐标:', windowX);
    console.log('窗口纵坐标:', windowY);

    mainWindow.on('closed', () => {
        app.quit();
    });
});

在这个例子中,mainWindow.getPosition() 返回一个包含窗口横坐标和纵坐标的数组。你可以根据需要访问这个数组的元素,获取窗口的位置。

如果你只关心窗口的横坐标或纵坐标,也可以使用 mainWindow.getBounds().x 和 mainWindow.getBounds().y 来分别获取窗口的横坐标和纵坐标。

BrowserWindow 属性

BrowserWindow is an EventEmitter.

It creates a new BrowserWindow with native properties as set by the options.

官方文档:https://www.electronjs.org/docs/latest/api/browser-window

optiondata typeinductiondefault value
widthInteger (optional)Window’s width in pixels.Default is 800.
heightInteger (optional)Window’s height in pixels.Default is 600.
xInteger (optional)(required if y is used) Window’s left offset from screen.Default is to center the window.
yInteger (optional)(required if x is used) Window’s top offset from screen.Default is to center the window.
useContentSizeboolean (optional)The width and height would be used as web page’s size, which means the actual window’s size will include window frame’s size and be slightly larger.Default is false.
centerboolean (optional)Show window in the center of the screen.Default is false.
minWidthInteger (optional)Window’s minimum width.Default is 0.
minHeightInteger (optional)Window’s minimum height.Default is 0.
maxWidthInteger (optional)Window’s maximum width.Default is no limit.
maxHeightInteger (optional)Window’s maximum height.Default is no limit.
resizableboolean (optional)Whether window is resizable.Default is true.
movableboolean (optional) macOS WindowsWhether window is movable. This is not implemented on Linux.Default is true.
minimizableboolean (optional) macOS WindowsWhether window is minimizable. This is not implemented on Linux.Default is true.
maximizableboolean (optional) macOS WindowsWhether window is maximizable. This is not implemented on Linux.Default is true.
closableboolean (optional) macOS WindowsWhether window is closable. This is not implemented on Linux.Default is true.
focusableboolean (optional)Whether the window can be focused.On Windows setting focusable: false also implies setting skipTaskbar: true. On Linux setting focusable: false makes the window stop interacting with wm, so the window will always stay on top in all workspaces.Default is true.
alwaysOnTopboolean (optional)Whether the window should always stay on top of other windowsDefault is false.
fullscreenboolean (optional)Whether the window should show in fullscreen. When explicitly set to false the fullscreen button will be hidden or disabled on macOS.Default is false.
fullscreenableboolean (optional)Whether the window can be put into fullscreen mode. On macOS, also whether the maximize/zoom button should toggle full screen mode or maximize window.Default is true.

Kiosk 模式介绍

Windows Kiosk模式只是Windows操作系统(OS)的一项功能,它将系统的可用性或访问权限仅限于某些应用程序。意思是,当我们在Windows上打开 Kiosk 模式时,它只允许一个应用程序运行,就像机场上的kiosk系统那样设置为仅运行Web浏览器,某些应用程序如PNR状态检查一个。

Kiosk模式的好处是,它允许企业仅在办公室,餐馆等运行特定的销售点(POS)应用程序,以阻止客户使用机器上的任何其他应用程序,除了他们已分配的应用程序。它不仅可以在windows 10上使用,而且还可以在Windows XP,Windows Vista,Windows 7和Windows 8.1中启用。

获取窗口尺寸

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

app.whenReady().then(() => {
    const mainWindow = new BrowserWindow({
        width: 800, height: 600,
    });

    const windowSize = mainWindow.getSize();
    const windowWidth = windowSize[0];
    const windowHeight = windowSize[1];

    console.log('窗口宽度:', windowWidth);
    console.log('窗口高度:', windowHeight);

    mainWindow.on('closed', () => {
        app.quit();
    });
});

在这个例子中,mainWindow.getSize()返回一个包含窗口宽度和高度的数组。你可以根据需要访问这个数组的元素,获取窗口的宽度和高度。

如果你只关心窗口的宽度或高度,也可以使用mainWindow.getBounds().width和mainWindow.getBounds().height来分别获取窗口的宽度和高度。

浏览器 require 问题

VM158 renderer_init:2 Electron Security Warning (Insecure Content-Security-Policy) This renderer process has either no Content Security Policy set or a policy with “unsafe-eval” enabled. This exposes users of this app to unnecessary security risks.

在这里插入图片描述

webPreferences Object (optional) - Settings of web page’s features.

  • devTools boolean (optional) - Whether to enable DevTools. If it is set to false, can not use BrowserWindow.webContents.openDevTools() to open DevTools. Default is true.
  • nodeIntegration boolean (optional) - Whether node integration is enabled. Default is false.
  • nodeIntegrationInWorker boolean (optional) - Whether node integration is enabled in web workers. Default is false. More about this can be found in Multithreading.

渲染模板:index.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>hello world</h1>
    <button id="btn">打开新的窗口</button>
    <script src="index.js"></script>
</body>
</html>

打开调试控制台:Ctrl + Shift + i 快捷键

在这里插入图片描述

可以发现 渲染进程的 console 在 渲染页面 打印,主进程的 console 在 终端 cmd 打印。

特别提醒!!!

在你将低版本的Electron升级至高版本时你一定会发现主进程中设置nodeIntegration为true后,渲染进程中依旧无法使用remote模块,如何解决?

出现这个问题是因为官方为了安全性,将 electron v12.0.0 的 contextIsolation 的默认值改了。所以今后要在渲染进程里调用 require 的话,还需要加上 contextIsolation: false 。

webPreferences: {
 	nodeIntegration: true,
    contextIsolation: false
}

contextIsolation boolean (optional) - Whether to run Electron APIs and the specified preload script in a separate JavaScript context. Defaults to true. The context that the preload script runs in will only have access to its own dedicated document and window globals, as well as its own set of JavaScript builtins (Array, Object, JSON, etc.), which are all invisible to the loaded content. The Electron API will only be available in the preload script and not the loaded page. This option should be used when loading potentially untrusted remote content to ensure the loaded content cannot tamper with the preload script and any Electron APIs being used. This option uses the same technique used by Chrome Content Scripts. You can access this context in the dev tools by selecting the ‘Electron Isolated Context’ entry in the combo box at the top of the Console tab.

然后重试,可以发现 require 可以使用了,但是出现新问题:
在这里插入图片描述

const { remote } = require('electron')

window.addEventListener("DOMContentLoaded", () => {
    const oBtn = document.getElementById("btn")
    oBtn.addEventListener('click', () => {
        console.log("hello world")
        const minWindow = new remote.BrowserWindow({
            width: 200, height: 150
        })

        minWindow.loadFile('mini.html')
    })
})

出现新的问题:
在这里插入图片描述

旧版本 - 解决方案:

webPreferences: {
	nodeIntegration: true,
	contextIsolation: false,
	enableRemoteModule: true
}

但是还是:

在这里插入图片描述

原因: enableRemoteModule 在官方文档 API 已经删除

较低版本的electron(v10以前的版本)

在主进程中设置nodeIntegration: true后,只需要从electron中引入remote即可

const remote = require('electron');

较高版本的electron(以19.0.8为例)

1、先安装模块@electron/remote (推荐淘宝镜像)

npm install --save @electron/remote

2、主进程中设置nodeIntegration:true,contextIsolation: false(如果是V10,则只要设置nodeIntegration为true即可),同时在创建窗口实例之后引入模块

require('@electron/remote/main').initialize()
require("@electron/remote/main").enable(win.webContents)

main.js

const win = new BrowserWindow({
    x: 200,
    y: 200,
    autoHideMenuBar: true,
    show: false,
    width: 800,
    height: 600,
    icon: './icon.ico',
    title: "hello world",
    webPreferences: {
        nodeIntegration: true,
        contextIsolation: false
    }
})

require('@electron/remote/main').initialize()
require("@electron/remote/main").enable(win.webContents)

在渲染进程中导入remote模块

const remote = require("@electron/remote")

WebContents #1 called ipcRenderer.sendSync() with REMOTE_BROWSER_GET_BUILTIN’ channel without listeners.

在 Electron 中,进程使用 ipcMain 和 ipcRenderer 模块,通过开发人员定义的“通道”传递消息来进行通信。 这些通道是 任意 (您可以随意命名它们)和 双向 (您可以在两个模块中使用相同的通道名称)的。

下面会用 进程间 通信 进行介绍。

窗口透明无边框

.创建BrowserWindow时指定transparent: true和frame: false和devTools: false

注意devTools可能会影响到transparent

mainWindow = new BrowserWindow({
	height: 960,
	width: 1820,
	transparent: true,
	resizable: false,
	frame: false,
	webPreferences: {
	    devTools: false,
	    nodeIntegration: true,
	    enablemotemodule: true
	}
})

Node 结合 Opencv

官网教程:https://www.npmjs.com/package/opencv4nodejs#how-to-install

How to install

npm install --save opencv4nodejs

如果采用 cnpm 执行如下

cnpm install --save opencv4nodejs

Native node modules are built via node-gyp, which already comes with npm by default. However, node-gyp requires you to have python installed. If you are running into node-gyp specific issues have a look at known issues with node-gyp first.

Important note: node-gyp won’t handle whitespaces properly, thus make sure, that the path to your project directory does not contain any whitespaces. Installing opencv4nodejs under “C:\Program Files\some_dir” or similar will not work and will fail with: “fatal error C1083: Cannot open include file: ‘opencv2/core.hpp’”!**

On Windows you will furthermore need Windows Build Tools to compile OpenCV and opencv4nodejs. If you don’t have Visual Studio or Windows Build Tools installed, you can easily install the VS2015 build tools:

npm install --global windows-build-tools

如果采用 cnpm 执行如下

cnpm install --global windows-build-tools

css 配置可拖拽区

应用程序需要在 CSS 中指定 -webkit-app-region: drag 来告诉 Electron 哪些区域是可拖拽的
在可拖拽区域内部使用 -webkit-app-region: no-drag 则可以将其中部分区域排除
拖动行为可能与选择文本冲突。 例如, 当您拖动标题栏时, 您可能会意外地选择标题栏上的文本。 为防止此操作, 您需要在可区域中禁用文本选择

.titlebar {
	-webkit-app-region: drag;
	-webkit-user-select: none;
}

在某些平台上,可拖拽区域不被视为窗口的实际内容,而是作为窗口边框处理,因此在右键单击时会弹出系统菜单。 要使上下文菜单在所有平台上都正确运行, 您永远也不要在可拖拽区域上使用自定义上下文菜单。

备注:如果你在某些页面设置了可拖拽区,跳转到一个新的页面,而这个新的页面没有设置可拖拽区,则会沿用上一页面的可拖拽区,感觉很奇怪,也没有相应的 dom 支持,就像取用的上一页面固定的像素区域一样(测试发现是这样,不准确之处请指正,谢谢)。如果拖拽区域不同,这种情况下,在新的页面中设置上拖拽区域即可。

electron-packager

命令行直接打包

electron-packager ./ map --platform=win32 --out=release --arch=ia32 --electron-version=1.8.4 --overwrite

执行命令 electron-packager --help 或者访问官网查看所有可配置参数

参数说明
map你将要生成的exe文件的名称
-platform=win32确定了你要构建哪个平台的应用(Windows、Mac 还是 Linux),可取的值有 darwin, linux, mas, win32
-arch=x64决定了使用 x86 (ia32)还是 x64(x64),还是两个架构都用
-icon=自定义.ico自定义设置应用图标
-out=./out指定打包文件输出的文件夹位置,当前指定的为项目目录下的 release 文件夹
-asar该参数可以不加,如果加上,打包之后应用的源码会以.asar格式存在
-app-version=1.0.0生成应用的版本号
-overwrite覆盖原有的build,让新生成的包覆盖原来的包
-ignore=node_modules如果加上该参数,项目里 node_modules 模块不会被打包进去
-electron-version 8.2.1指定当前要构建的 electron 的电子版本(不带"v"),需要和当前的版本一致,具体可以在 package.json 文件中查看,可以不加该参数,如果不一致,会自动下载

在 package.json 文件中配置

"scripts": {
    "package":"electron-packager . HelloWorld --platform=win32 --arch=x64 --icon=computer.ico --out=./out --asar --app-version=1.0.0 --overwrite --ignore=node_modules"
}

在命令行中输入:npm run package

在这里插入图片描述

resourse 文件夹存放源代码,若不想人查看源代码,可在打包时加上 asar,用来对 resources 文件进行简单加密。

electron remote

在使用 electron 当中的 remote 模块时遇到了一个巨坑:remote 模块不存在。在国内的问答网站中皆未找到解决办法,最后在 stack overflow 中找到了解决办法。

原因是在 Electron 10.x 中,enableRemoteModule 的默认值为 false,也就是默认情况下是不支持使用 remote 模块的,因此使用 remote 模块的应用程序需要将 enableRemoteModule 显式设置为 true 才有效。

mainWindow = new BrowserWindow({
	width:400,
	height:400,
	webPreferences: {     
	  	contextIsolation: false,
	    nodeIntegration: true,
	    devTools: true,
	    webSecurity: false,
	  	enableRemoteModule: true 
	}
})

在 Electron 中,remote 模块曾经用于在主进程和渲染进程之间共享数据和方法,使得开发者可以在渲染进程中直接访问主进程的 API。然而,从 Electron 10 开始,出于安全考虑,remote 模块默认被禁用了。

c

使用 IPC 通信

使用 Electron 的 IPC(进程间通信)机制来在主进程和渲染进程之间传递数据和方法。您可以使用 ipcMain 和 ipcRenderer 模块来发送和接收消息。

使用 contextBridge

如果您希望从主进程暴露一些 API 给渲染进程,可以使用 contextBridge。这允许您在渲染进程的预加载脚本中定义一个安全的上下文隔离层,从而暴露必要的 API,同时隐藏其他可能带来安全风险的 API。

回退旧版本 Electron

如果您确实需要 remote 模块,并且您的项目可以容忍使用旧版本的 Electron,您可以考虑回退到支持 remote 模块的 Electron 版本。但请注意,这样做可能会使您的应用面临更多的安全风险。

Electron dialog 弹窗

渲染进程 render.js

const ipcRenderer = require("electron").ipcRenderer;

ipcRenderer.sendSync("error-dialog", { title: "错误", content: "文件不存在!"})

主进程 main.js

const { ipcMain, dialog } = require('electron');

ipcMain.on('error-dialog', (event, params) => {
    dialog.showErrorBox(...Object.values(params))
})
  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

唤醒手腕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值