在 Vue3 + Electron 中使用预加载脚本(preload)
创始人
2024-12-27 09:38:26
0

文章目录

      • 一、什么是预加载脚本(preload),为什么我们需要它
      • 二、通过预加载脚本暴露相关 API 至渲染进程
        • 1、实现获取系统默认桌面路径功能
        • 2、向剪切板写入内容
        • 3、使用系统默认浏览器访问目标 url
        • 4、使用文件选择对话框
      • 三、参考资料

一、什么是预加载脚本(preload),为什么我们需要它

根据 Electron 官方提供的相关说明,我们可以将预加载脚本理解成是主进程和渲染进程间的桥梁。通常出于安全性的角度考虑,我们使用预加载脚本来安全地将 Node.js 模块或第三方库的 API 暴露至渲染进程中。

有时,我们可能为了在渲染进程中使用 Node.js 相关模块而关闭上下文隔离和为页面集成 Node.js 环境,但是这种方式官方并不推荐:

// 不推荐 const mainWindow = new BrowserWindow({   webPreferences: {     // 关闭上下文隔离     contextIsolation: false,     // 为页面集成 Node.js 环境     nodeIntegration: true,   } })  mainWindow.loadURL('https://example.com') 

官方推荐的使用预加载脚本(preload)暴露相关 API,以使用 Node.js 的模块功能:

// 推荐 const mainWindow = new BrowserWindow({   webPreferences: {     preload: path.join(app.getAppPath(), 'preload.js')   } })  mainWindow.loadURL('https://example.com') 

关于预加载脚本的更多介绍参见:https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload
关于安全方面的更多介绍参见:https://www.electronjs.org/zh/docs/latest/tutorial/security

二、通过预加载脚本暴露相关 API 至渲染进程

实现目标:

  • 获取系统默认桌面路径功能
  • 向剪切板写入内容
  • 使用系统默认浏览器访问目标 url
  • 使用文件选择对话框

项目通过 electron-vite-vue 构建,详情可见:https://blog.csdn.net/qq_45897239/article/details/138490747

准备工作,在主进程 main.ts 文件中导入 preload 相关文件:

// electron/main.ts function createWindow() {     win = new BrowserWindow({         width: 1200,         height: 700,         minWidth: 885,         minHeight: 580,         icon: path.join(process.env.VITE_PUBLIC, "electron-vite.svg"),         webPreferences: {             // 导入 preload 相关文件             preload: path.join(__dirname, "preload.mjs"),         },         // 隐藏菜单栏 按 Alt 键显示         autoHideMenuBar: true,     });     // 程序启动后开启 开发者工具     // win.webContents.openDevTools();      // 关闭菜单栏     // Menu.setApplicationMenu(null);      if (VITE_DEV_SERVER_URL) {         win?.loadURL(VITE_DEV_SERVER_URL);     } else {         win?.loadFile(path.join(RENDERER_DIST, "index.html"));     } } 
1、实现获取系统默认桌面路径功能

preload.ts 文件中通过 contextBridge 对外暴露自定义 API。

// electron/preload.ts import { ipcRenderer, contextBridge } from "electron";  contextBridge.exposeInMainWorld("electronAPI", {     // 获取系统默认桌面路径     getDesktopPath: async () => {         try {             return await ipcRenderer.invoke("get-desktop-path");         } catch (error) {             console.error("Failed to get desktop path:", error.message);         }     },     ... }); 

ipcRenderer.invoke 允许渲染进程向主进程发送事件或消息,并且接收主进程返回的数据。

可以直接在主进程中使用 ipcMain.handle() 监听渲染进程发送来的消息:

// electron/main.ts import { app, ipcMain } from "electron"; ... app.whenReady().then(async () => {     try {         ...         createWindow();         // get-desktop-path => 获取系统桌面路径         ipcMain.handle("get-desktop-path", () => {             return app.getPath("desktop");         });     } catch (error) {         console.error("Failed to start server:", error);     } }); 

调用 API 获取系统桌面路径:

 

注意: 可能会出现 ts 报错

属性“electronAPI”在类型“Window & typeof globalThis”上不存在。你是否指的是“Electron”?ts-plugin(2551) electron.d.ts(12, 19): 在此处声明了 "Electron"。 

解决方案

vite-env.d.ts 中追加以下内容即可:

declare interface Window {     electronAPI: any } 
2、向剪切板写入内容

定义相关 API:

// electron/preload.ts import { ipcRenderer, contextBridge } from "electron";  contextBridge.exposeInMainWorld("electronAPI", {     // 向剪切板写入内容     clipboardWriteText: async (text) => {         try {             await ipcRenderer.invoke("write-to-clipboard", text);         } catch (error) {             console.error("Failed to write to clipboard:", error.message);         }     },,     ... }); 

主进程中监听:

// electron/main.ts import { app, ipcMain, clipboard } from "electron"; ... app.whenReady().then(async () => {     try {         ...         // write-to-clipboard => 向剪切板写入内容         ipcMain.handle("write-to-clipboard", (event, text) => {             clipboard.writeText(text);         });     } catch (error) {         console.error("Failed to start server:", error);     } }); 

使用:

 
3、使用系统默认浏览器访问目标 url

定义相关 API:

// electron/preload.ts import { ipcRenderer, contextBridge } from "electron";  contextBridge.exposeInMainWorld("electronAPI", {     // 使用系统默认浏览器访问目标 url     openBrowserByUrl: async (url) => {         try {             await ipcRenderer.invoke("open-browser-by-url", url);         } catch (error) {             console.error("Failed to open browser:", error.message);         }     },     ... }); 

主进程中监听:

// electron/main.ts import { app, ipcMain, shell } from "electron"; ... app.whenReady().then(async () => {     try {         ...         // open-browser-by-url => 使用系统默认浏览器访问目标 url         ipcMain.handle("open-browser-by-url", async (event, url) => {             await shell.openExternal(url);         });     } catch (error) {         console.error("Failed to start server:", error);     } }); 

使用:

 
4、使用文件选择对话框

定义相关 API:

// electron/preload.ts import { ipcRenderer, contextBridge } from "electron";  contextBridge.exposeInMainWorld("electronAPI", {     // 打开文件保存对话框 返回文件保存路径     openFileSaveDialog: async (path) => {         try {             return await ipcRenderer.invoke("open-save-dialog",path);         } catch (error) {             console.error("Failed to open save dialog:", error.message);         }     },     ... }); 

此处需要将文件对话框设置为顶层窗口,否则用户关闭应用程序后,该窗口依然存在。由于将对话框设置为顶层对话框需要win实例,所以使用函数方式导出初始化。设置为顶层对话框后,防止对话框被多次打开和未关闭对话框时的其他窗口操作。

可以在 electron 文件夹下创建一个 ipcHandlers.ts 文件,该文件内放置主进程需要监听的渲染进程发送来的消息,后续再导入 main.ts 主进程文件中。

// electron/ipcHandlers.ts import { app, ipcMain, dialog, BrowserWindow } from "electron";  // 可以在此文件内放置需要监听的来自渲染进程的消息 // get-desktop-path => 获取系统桌面路径 ipcMain.handle("get-desktop-path", () => {     ... });  export function initIpcHandlerDialog(win: BrowserWindow) {     // open-save-dialog => 打开文件保存对话框     ipcMain.handle("open-save-dialog", async (event, path) => {         try {             // 打开保存文件对话框             const result = await dialog.showOpenDialog(win, {                 // 对话框标题                 title: "选择文件保存目录",                 // 确认按钮                 buttonLabel: "选择目录",                 // 默认文件路径                 defaultPath: app.getPath("desktop"),                 // 只允许选择文件夹                 properties: ["openDirectory"],                 // 文件过滤器,定义可以选择哪些类型的文件                 filters: [{ name: "All Files", extensions: ["*"] }]             });             if (result) {                 if (result.canceled) {                     console.log("用户取消了保存操作");                     // 如果用户取消了保存操作,则返回之前的保存路径,如若为空,则使用默认值                     if (!path) {                         path = app.getPath("desktop");                     }                     return path;                 } else {                     const filePath = result.filePaths[0];                     console.log("用户选择了保存路径:", filePath);                     return filePath;                 }             }         } catch (error) {             console.log("文件对话框打开失败:" + error);             // 获取桌面默认路径并返回             return app.getPath("desktop");         }     }); } 

在主进程中导入:

// electron/main.ts import { app, BrowserWindow, ipcMain } from "electron"; ... // 导入相关功能模块 import "./ipcHandlers.ts"; import { initIpcHandlerDialog } from "./ipcHandlers.ts";  ...  app.whenReady().then(async () => {     try {         ...         createWindow();         // 初始化对话框,将弹出对话框设置为顶层状态         initIpcHandlerDialog(win);     } catch (error) {         console.error("Failed to start server:", error);     } }); 

使用:

 

该方法传递了一个 defaultPath 参数,用于处理当用户点击了取消文件选择对话框时,使用的默认文件保存路径。

效果展示:

效果展示

三、参考资料

  • electron - ipcRenderer
  • electron - preload
  • electron - security

相关内容

热门资讯

推荐一款!金花房卡怎么购买荣耀... 荣耀联盟是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:【3329006910】或QQ:332900...
玩家攻略,金花房卡官网桃花大厅... 玩家攻略,金花房卡官网桃花大厅/房卡怎么购买Sa9Ix苹果iPhone 17手机即将进入量产阶段。有...
ia实测“微信拼三张房卡怎么获... 金牛座金花是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:44346008许多玩家在游戏中会购买房卡...
科普!微信上打炸金花房卡找谁买... 微信游戏中心:大牌九房卡,添加微信【55051770】,进入游戏中心或相关小程序,搜索“微信大牌九房...
头条推荐!牛牛房卡制作链接火星... 您好!微信火星大厅/新道游大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(火星大厅/新...
终于知道”新好游低价获取分享房... 第二也可以在游戏内商城:在游戏界面中找到 “微信金花,斗牛链接房卡”“商城”选项,选择房卡的购买选项...
IA解析/金花微信链接市场价格... 今 日消息,毛豆互娱房卡添加微信33549083 苹果今日发布了 iOS 16.1 正式版更新,简单...
ia攻略/金花房卡批发价玄灵大... 玄灵大厅房卡更多详情添加微:33549083、 2、在商城页面中选择房卡选项。 3、根...
科普!微信群打金花链接房卡,微... 微信游戏中心:牛牛房卡,添加微信【33903369】,进入游戏中心或相关小程序,搜索“微信牛牛房卡”...
终于知道”美人有挂吗“新道游房... 终于知道”美人有挂吗“新道游房间卡怎么购买微信房卡充值 添加房卡批售商:微【113857776】复制...
一分钟推荐“如何在微信上购买金... 新荣耀是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:44346008许多玩家在游戏中会购买房卡来享...
玩家攻略,游戏推荐斗牛房卡出售... 微信游戏中心:海贝大厅/新天道房卡在哪里买打开微信,添加客服微信【88355042】,进入游戏中心或...
科普!创建微信链接金花房卡,微... 微信游戏中心:牛牛房卡,添加微信【8488009】,进入游戏中心或相关小程序,搜索“微信牛牛房卡”,...
终于知道”超稳无敌哪里有详细房... 第二也可以在游戏内商城:在游戏界面中找到 “微信金花,斗牛链接房卡”“商城”选项,选择房卡的购买选项...
正版授权!金花房卡专卖店华山大... 您好!微信华山大厅大厅链接获取房卡可以通过以下几种方式购买: 1.微信渠道:(华山大厅)大厅介绍:...
炸金花房卡专卖店联系方式/微信... 微信炸金花是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:15984933许多玩家在游戏中会购买房卡...
终于知道”新众亿房卡购买“金花... 终于知道”新众亿房卡购买“金花房卡哪里是有卖 微信牛牛房卡客服微信号微信游戏中心打开微信,添加客服【...
科普!微信链接金花房卡在哪买的... 微信游戏中心:拼三张房卡,添加微信【55051770】,进入游戏中心或相关小程序,搜索“微信拼三张房...
房卡必备教程“炸金花房卡专卖店... 皇豪互娱是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:44346008许多玩家在游戏中会购买房卡来...
重大通报,游戏微信牛牛房卡水仙... 水仙大厅是一款非常受欢迎的棋牌游戏,咨询房/卡添加微信:【3329006910】或QQ:332900...