介绍了 Electron+react 开发桌面端应用时的一些问题和解决方法,例如:自定义导航栏、打包排除 node_modules 文件夹、解决音视频自动播放问题、解决 antd modal 弹框鼠标穿透事件等。
自定义导航栏
windows 默认的导航栏事件有:最大化、最小化、关闭,默认显示在右上角。
但项目中不需要最小化,不然 UI 适配有问题,而且这个样式也不太适配项目主题,因此自定义的实现是必要的了
- 首先需要隐藏导航栏,在 main.js 中配置:
frame: false,同时需要注释titleBarOverlay: true的配置,不然不起作用
const createWindow = () => {
// 创建浏览窗口
win = new BrowserWindow({
show: false, // 默认不显示
titleBarStyle: "hidden", // mac隐藏导航栏
// titleBarOverlay: true, // win系统隐藏导航栏
autoHideMenuBar: true, // 自动隐藏菜单栏
frame: false, // window隐藏导航栏 titleBarOverlay同时也要隐藏
// 预加载
webPreferences: {
// 需要在渲染进程中使用node
nodeIntegration: true,
contextIsolation: false,
// 解决报错:DOMException: play() failed because the user didn't interact with the document first.
autoplayPolicy: "no-user-gesture-required", // 禁用自动播放限制
},
});
// 打开后最大化显示
win.maximize();
win.show();
// electron-builder打包启动文件
win.loadFile(path.join(__dirname, "./build/index.html"));
// 打开开发工具
// win.webContents.openDevTools();
};
- 自定义关闭事件实现:通过
ipcRenderer和ipcMain来实现自定义的关闭事件。
(1)在渲染进程(index.tsx)中发送关闭事件: 在渲染进程中,当用户触发关闭操作时,通过 ipcRenderer 发送一个自定义的关闭事件。
// 定义ipcRenderer
let ipcRenderer: any;
if (window.require) {
const electron = window.require("electron");
ipcRenderer = electron.ipcRenderer;
}
// 发送 defineClose 事件通知
if (ipcRenderer) {
// 发送 defineClose 事件
ipcRenderer.send("defineClose");
}
(2)在主进程中,添加一个监听器来处理 defineClose 事件,并执行相应的关闭操作。
// main.js文件
const {
app,
BrowserWindow,
ipcMain, // 导入 ipcMain 模块
} = require("electron");
let win;
const createWindow = () => {
// 创建浏览窗口
win = new BrowserWindow({});
};
// 只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口
app.whenReady().then(() => {
// 调用该函数来打开窗口
createWindow();
// 监听 defineClose 事件
ipcMain.on("defineClose", () => {
// 执行关闭操作
if (win) {
win.close(); // 关闭窗口
}
});
});
打包排除 node_modules 文件夹
默认情况下,使用 electron-builder 打包 Electron 应用时,打包后的应用会包含 node_modules 文件夹,这会导致打包后的应用体积过大,而且打包时间也会很漫长。因此,我们需要排除 node_modules 文件夹,只打包我们的项目代码。
如上图所示:会将 node_modules 打包到win-ia32-unpacked/resource/app下。要解决这个问题,需要在 package.json 中添加如下配置:"files": ["!node_modules"],排除该文件夹
{
"productName": "demo", // 项目名
"version": "1.0.1", // 项目版本号
"main": "main.js", // 入口文件
"homepage": ".", // 解决本地运行白屏问题
"scripts": {
"electron-start": "nodemon --exec electron .", // 热启动运行本地服务命令,本地调试使用
"packOs": "electron-builder --mac", // mac系统打包命令
"packWin64": "electron-builder --win --x64", // win64位系统打包命令;不能在32位系统中安装,安装时会报错:需要64位操作系统
"packWin32": "electron-builder --win --ia32" // win32位系统打包命令,可以在64位系统中安装
},
"build": {
"productName": "demo", // 应用名称
"asar": false, // 是否压缩build文件夹。调试时,可配置为false,查看是否正确打包
"artifactName": "${productName}-setup-${version}.${ext}", // 自定义生成exe安装包名称
"directories": {
"output": "dist-${version}" // 打包输出文件夹
},
// 打包文件范围
"files": [
"build/**/*", // 项目打包后的文件夹
"./main.js", // 入口文件
"!node_modules" // 排除node_modules文件
],
"extraMetadata": {
"main": "./main.js"
},
"mac": {
"icon": "build/icon.png" // 应用图标 512*521
},
"win": {
"icon": "build/icon.ico" // 应用图标 256*256
}
},
"devDependencies": {
"electron": "21.4.4", // 指定版本,解决win7打包报错问题
"electron-builder": "24.6.4"
}
}
解决音视频自动播放问题
许多现代浏览器出于用户体验和性能考虑,默认情况下会限制视频的自动播放,特别是带有声音的视频。
如果视频没有声音或设置了静音,浏览器可能会允许自动播放。
报错信息如下所示:NotAllowedError: play() failed because the user didn't interact with the document first.
- 在浏览器中,在用户与页面交互后(如点击按钮),浏览器会允许音频或视频自动播放。或者可以配置 muted 属性,先静音播放,然后与用户交互后,再打开声音。
// 定义组件
<video
ref={videoRef}
src="./media/bg.mp4"
autoPlay
// muted
onEnded={handleVideoEnd}
onCanPlay={handleCanPlay}
/>;
// 当视频可以播放时的处理函数
const handleCanPlay = () => {
videoRef.current
?.play()
.then(() => {
// 如果视频被静音 显示提示信息
if (videoRef.current?.muted) {
handleTip();
}
})
.catch((err: any) => {
// 自动播放失败 显示提示信息
handleTip();
});
};
const handleTip = () => {
modal.info({
title: "温馨提示",
content: (
<div>
<p>您的浏览器限制了视频的自动播放</p>
<p>为了更好的观看体验,视频将默认静音播放</p>
<p>请点击“知道了”以开始播放视频</p>
</div>
),
onOk: () => {
if (!videoRef.current) return;
// 触发手动播放
videoRef.current.muted = false;
videoRef.current.play();
},
});
};
- 在 Electron 中,如果不配置的话,也需要手动触发音频或视频的播放,才能实现自动播放。
而配置的话,只有一行代码的事,不需要上述的用户交互处理了。在 main.js 中添加如下配置:autoplayPolicy: 'no-user-gesture-required'
const createWindow = () => {
// 创建浏览窗口
win = new BrowserWindow({
webPreferences: {
autoplayPolicy: 'no-user-gesture-required' // 打开自动播放限制
},
});
antd modal 鼠标穿透事件
当 antd 的模态对话框(modal)打开时,默认情况下会在背景上覆盖一层遮罩(通常是半透明的黑色或灰色层)。这层遮罩的作用是防止用户与模态对话框下方的内容进行交互,从而确保用户必须先处理模态对话框中的内容。
这种设计是为了提高用户体验,避免用户在未处理重要信息的情况下继续操作其他内容。
但有时,可能希望用户在模态对话框打开时仍然能够与背景内容进行交互。例如,用户可能需要查看或操作背景中的某些信息,然后再关闭模态对话框。
可以设置 pointer-events 属性为 none,这样,遮罩层将不再拦截鼠标事件,鼠标事件会穿透到背景内容,用户可以继续与背景内容进行交互。
pointer-events:控制元素是否响应鼠标事件。当设置为 none 时,元素及其所有子元素都不会接收任何鼠标事件,鼠标事件会穿透到下面的元素。
.ant-modal-wrap {
// 允许弹框底部操作
pointer-events: none;
}
其他文章汇总: