注册自定义协议并拦截基于现有协议的请求实现与file同等级的协议
需要实现的是把电脑本地的图片读取显示,直接返回file://浏览器不支持.,net:error

可以用保存并返回base64(直接nodejs的fs读取文件返回文件流/转化为base64通过invoke返回给vue,字符太多,但不需要协议访问),设置electron的自定义协议通过图片的访问(类http,需要显示时加载)
数据库存的差异化短路径

设置electron的自定义协议通过图片的访问,官网示例
https://www.electronjs.org/zh/docs/latest/api/protocol#protocolregisterfileprotocolscheme-handler
1.设置一个自定义的以app为标识的拦截,
当vue端需要获取这个路径的图片时,卸载index.js的protocol.handle('app', 将触发,request返回要访问的url,例(app://books/cover/books_4_cover_image_1768186177917_ueh6f8uxf.jpg)
在这里拆解这个url,转成绝对路径例(J:\MyScript\book-write\front_electron_book\editor_books_app\uploadImage\books\cover),通过net.fetch访问系统并返回promise
// 导入Electron核心模块
import { app, shell, BrowserWindow, ipcMain, Notification, protocol, session,net } from 'electron'
import { join } from 'path'
import path from 'path'
import url from 'url'
import fs from 'fs'
// 设置协议为标准协议
protocol.registerSchemesAsPrivileged([
{
scheme: 'app',
privileges: {
standard: true,
secure: true,
supportFetchAPI: true
}
}
])
// ============ app ready事件处理 ============
app.whenReady().then(() => {
electronApp.setAppUserModelId('com.electron.bookmanager')
// 设置窗口快捷键
app.on('browser-window-created', (_, window) => {
optimizer.watchWindowShortcuts(window)
})
//初始化IPC处理器
setupIpcHandlers(ipcMain)
console.log('创建窗口')
//定义handle,app为标识,每次访问触发,需要返回promise
protocol.handle('app', (request) => {
try {
//拼接本地资源路径
const filePath = request.url.slice('app://'.length)
let dirUrl = path.join(initPath('uploadImage'), filePath)
let abUrl = url.pathToFileURL(dirUrl)
//使用electron自带的net的fetch方法访问系统级操作网络请求,直接返回,版本太老可能没有net支持
return net.fetch(abUrl.toString())
//不能用net依旧是读文件自己返回promise,data可转成base64
// const data = fs.readFileSync(dirUrl)
// // 设置正确的 MIME 类型
// const ext = path.extname(dirUrl).toLowerCase()
// const mime = {
// '.jpg': 'image/jpeg',
// '.jpeg': 'image/jpeg',
// '.png': 'image/png',
// '.gif': 'image/gif'
// }[ext] || 'application/octet-stream'
// return new Response(data, {
// headers: { 'Content-Type': mime }
// })
} catch (error) {
console.error('Failed to load file:', error)
return new Response('Not Found', { status: 404 })
}
})
// 其他逻辑
})
2.修改vue部分的index.html自带的总入口文件meta标签
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<title>测试</title>
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self' 'unsafe-inline'
'unsafe-eval' blob: data: file: app:;
img-src 'self' data: blob: file: app: http: https:;
style-src 'self' 'unsafe-inline';
script-src 'self' 'unsafe-eval' 'unsafe-inline';
connect-src 'self' ws: wss: http: https:;
font-src 'self' data:;
media-src 'self' data: blob:;"/>
<!-- content="default-src 'self';
script-src 'self';
style-src 'self'
'unsafe-inline';
img-src 'self' data:"
/> -->
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
3.vue前端使用,设置正确的
background-position:0%;
background-size: inherit;
html
<div class="book-card" v-for="(item, index) in books" :key="index"
:style="{backgroundImage:`url(${getImageUrl(item.coverImageUrl)})`}"
></div>
js
function getImageUrl(imagePath) {
console.log(imagePath)
return "app://" + imagePath
}
css
.book-card {
background: var(--color-theme-second);
width: 100px;
height: 120px;
margin-bottom: 30px;
color: var(--color-theme-text);
position: relative;
background-position:0%;
background-size: inherit;
}