1. 为什么浏览器无法获取文件绝对路径?
浏览器出于安全考虑,设计了一套严格的沙箱机制。当你用<input type="file">选择文件时,浏览器只会返回一个虚拟路径(比如C:\fakepath\test.txt),而不是真实的D:\documents\test.txt。这个限制是为了防止恶意网站通过JavaScript窃取你的本地文件系统信息。
我在实际项目中遇到过更棘手的情况:客户需要上传整个文件夹并保留目录结构。这时候相对路径完全不够用,必须拿到完整的绝对路径才能重建文件夹层级。试过各种Hack方法后,最终发现只有Electron能真正突破这个限制——因为它本质上是一个带Chromium内核的Node.js运行时环境。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. Electron环境搭建与Vue3集成
2.1 项目初始化
先创建一个标准的Vue3项目:
bash复制npm init vue@latest vue3-electron-path
cd vue3-electron-path
npm install
然后添加Electron依赖:
bash复制npm install electron electron-builder --save-dev
关键配置在vue.config.js中:
javascript复制module.exports = {
pluginOptions: {
electronBuilder: {
nodeIntegration: true, // 启用Node.js集成
contextIsolation: false // 关闭上下文隔离
}
}
}
踩坑提醒:如果你用的是Electron 12+版本,还需要额外配置sandbox: false。我曾在版本升级时被这个配置卡了半天,控制台一直报require is not defined的错误。
2.2 主进程与渲染进程通信
在background.js(Electron主进程)中添加文件对话框逻辑:
javascript复制const { app, BrowserWindow, ipcMain, dialog } = require('electron')
ipcMain.handle('open-dialog', async (event, options) => {
return await dialog.showOpenDialog({
properties: ['openFile', 'multiSelections'],
...options
})
})
在Vue组件中(渲染进程)这样调用:
javascript复制import { ipcRenderer } from 'electron'
const selectFiles = async () => {
const result = await ipcRenderer.invoke('open-dialog', {
title: '选择PDF文件',
filters: [{ name: 'PDF', extensions: ['pdf'] }]
})
console.log(result.filePaths) // 这里就是绝对路径数组
}
3. 开发模式下的特殊处理
3.1 区分运行环境
直接在浏览器中运行会报ipcRenderer is not defined,需要做环境判断:
javascript复制const useElectronAPI = () => {
if (window.require) {
return window.require('electron')
}
return null
}
// 使用示例
const electron = useElectronAPI()
if (electron) {
electron.ipcRenderer.send('message')
}
3.2 热重载配置
在background.js中加入这段代码,可以保持Vue的热更新功能:
javascript复制if (process.env.WEBPACK_DEV_SERVER_URL) {
win.loadURL(process.env.WEBPACK_DEV_SERVER_URL)
if (!process.env.IS_TEST) win.webContents.openDevTools()
} else {
win.loadFile('index.html')
}
4. 生产环境打包优化
4.1 白名单机制
出于安全考虑,应该限制可访问的目录范围。在background.js中添加路径校验:
javascript复制const ALLOWED_PATHS = [
process.env.HOME,
process.env.USERPROFILE,
'/Users/Shared'
]
ipcMain.handle('safe-open-dialog', (even
