简介
Electron 允许你在渲染进程中使用一些特定于桌面的原生模块,例如文件对话框、系统托盘、菜单等。这些模块提供了更好的用户体验。结合了 Node.js 的文件系统模块(fs)和浏览器环境的 Web API,导入导出文件功能就使用到 dialog 和 fs。
fs和dialog使用语法
- 使用 Node.js 的 fs 模块
通常使用nodejs的fs进行文件操作,如读取、写入、删除等。
const fs = require('fs');
// 读取文件
fs.readFile('path/to/file.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
// 写入文件
fs.writeFile('path/to/newfile.txt', 'Hello, Electron!', (err) => {
if (err) throw err;
console.log('File has been written.');
});
// 删除文件
fs.unlink('path/to/file.txt', (err) => {
if (err) throw err;
console.log('File has been deleted.');
});
- 使用 Electron 的 dialog 模块选择文件
dialog 模块来创建文件选择对话框,让用户选择文件或目录。一旦用户选择了文件,你就可以使用 Node.js 的 fs 模块来进行进一步的文件操作。
const { dialog } = require('electron');
// 打开文件选择对话框
dialog.showOpenDialog({ properties: ['openFile'] }).then((result) => {
const filePath = result.filePaths[0];
// 在这里可以使用 fs 模块进行文件操作
// 例如读取文件内容、写入文件等
});
导入导出
导出:获取文件数据 > 填写文件名 > 打开文件选择对话框 > 选择文件保存路径 >写入文件
导入:打开文件选择对话框 > 选择导入文件 > 读取文件
-
通信 IPC 机制
contextBridge将 进程事件API 暴露给渲染器(htmlvue渲染文件通过window对象可调用api)
app对象控制应用程序的事件生命周期
BrowserWindow对象创建浏览器窗口
WebPreferences对象是 BrowserWindow 构造函数的一个选项,用于配置渲染进程的 Web 视图(WebContents)的行为。webPreferences 允许你配置诸如安全性、缓存、网络、用户界面等方面的设置。 -
electron部分
(1)入口文件
打开一个窗口mainWin,加载渲染文件winURL,主进程ipcMain添加事件
同步returnValue,异步reply,remote
//main.ts
const { app, BrowserWindow, ipcMain, dialog } = require("electron");
//@ts-ignore
const fs = require("fs");
let mainWin;
//环境变量判断
const NODE_ENV = process.env.NODE_ENV;
let winURL =
NODE_ENV === "development"
? "http://localhost:5173/"
: `file://${path.join(__dirname, "../dist/index.html")}`;
//console.log(__dirname); 上述代码会输出当前文件所在的目录路径
const createMainWindow = () => {
mainWin = new BrowserWindow({
width: 1920,
height: 1080,
webPreferences: {
//@ts-ignore
nodeIntegration: process.env.ELECTRON_NODE_INTEGRATION,
contextIsolation: !process.env.ELECTRON_NODE_INTEGRATION,
nodeIntegrationInWorker: true,
webSecurity: false,
preload: path.join(__dirname, "preload.ts"),//加载渲染进程文件
},
title: "测试",
show: false,//控制窗口显示与隐藏
});
mainWin.loadURL(winURL);
if (NODE_ENV === "development") {
mainWin.webContents.openDevTools();//打开浏览器调试工具
}
mainWin.once("ready-to-show", () => {
mainWin.show();
mainWin.maximize();
});
};
app.whenReady().then(() => {
mainWin = null;
createMainWindow();
});
ipcMain.on("toMain", onMain);
function onMain (event, res) {
if (res.method == "showExportOpenDialog") showExportOpenDialog(event);
else if (res.method == "showImportOpenDialog") showImportOpenDialog(event);
};
function showExportOpenDialog (event) {
const dirPath = dialog.showOpenDialogSync({
properties: ["openDirectory"],
});
if (dirPath === undefined) return;
event.reply("getExportFilePath", {
dirPath: dirPath,
});
};
function showImportOpenDialog (event) {
const filePath = dialog.showOpenDialogSync({
properties: ["openFile"],
});
if (filePath === undefined) return;
event.reply("getImportFileName", {
filePath: filePath,
});
};
(2)渲染器 ipcRenderer
const { contextBridge, ipcRenderer } = require("electron");
const os = require("os");
//@ts-ignore
const fs = require("fs");
contextBridge.exposeInMainWorld("api", {
send: (channel, data) => {
// whitelist channels
let validChannels = [
"toMain",
];
if (validChannels.includes(channel)) {
ipcRenderer.send(channel, data);
}
},
receive: (channel, func) => {
let validChannels = [
"fromMain",
"getExportFilePath",
"getImportFileName",
];
if (validChannels.includes(channel)) {
// Deliberately strip event as it includes `sender`
ipcRenderer.on(channel, (event, ...args) => func(...args));
}
},
});
contextBridge.exposeInMainWorld("fs", fs);
contextBridge.exposeInMainWorld("os", os);
- fs 文件操作
//IO.ts
const importData = (filePath: string) => {
//读取指定路径的数据
//@ts-ignore
const fileData = JSON.parse(
//@ts-ignore
window.fs.readFileSync(filePath[0], "utf-8", (err: any) => {
if (err) alert("导入数据失败,请联系管理员!");
})
);
return fileData ? fileData : "";
};
const exportData = (filePath: string, data: any) => {
const geojson = data;
//拿着文件写入指定路径
//@ts-ignore
window.fs.writeFile(filePath, JSON.stringify(geojson), "utf8", (err: any) => {
if (err) {
alert("导出数据失败,请联系管理员!");
return 0;
}
});
return 1;
};
export default {
importData,
exportData,
};
- 渲染文件vue
按钮绑定以下事件,通过 window 调取 electron 的 dialog 相关事件获取文件路径,再通过 fs 进行文件读写操作
// 选择导出文件
function changeExportFile(index) {
if (!exportData.value) return;
var regex = new RegExp(/[\u4e00-\u9fa5_a-zA-Z0-9]$/);
if (!regex.test(exportFileName.value)) {
msg.showErrorMesBox(
"请输入正确格式导出文件名(仅支持汉字,数字,字母,下划线)"
);
return;
}
//@ts-ignore
window.api.send("toMain", {
method: "showExportOpenDialog",
});
//@ts-ignore
window.api.receive("getExportFilePath", (res: any) => {
if (res.dirPath) {
exportPath.value = res.dirPath;
console.log("导出", exportFileName.value, exportPath.value);
IO.exportData(exportPath.value + '/' + exportFileName.value + '.json',exportData.value);
}
});
}
// 选择导入文件
function openImportFile() {
//@ts-ignore
window.api.send("toMain", {
method: "showImportOpenDialog",
});
//@ts-ignore
window.api.receive("getImportFileName", (res: any) => {
if (res.filePath) {
importPath.value = res.filePath[0];
let fileData = IO.importData(res.filePath);
if (fileData) {
importInfo.value = fileData;
console.log("importInfo.value", importInfo.value);
}
}
});
}