打包后窗口白屏
问题描述:使用electron打包后,运行程序后窗口白屏
原因
生产环境加载窗口使用的是loadFile方法,而开发环境使用的是loadURL方法,导致路径不一致,导致白屏。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| const { app, BrowserWindow } = require('electron') routers.push( new EventRoute('tool', 'event', (api, data = {}) => { const toolWindow = new BrowserWindow({ width: 300, height: 400, resizable: false, autoHideMenuBar: true, webPreferences: { nodeIntegration: true, devTools: true } }) const winURL = process.env.NODE_ENV === 'development' ? 'http://localhost:5173/#/tool' : `${path.join(__dirname, '../dist/index.html#tool')}` toolWindow.loadURL(winURL) }) )
|
解决方法
路由添加对应路径
1 2 3 4 5
| { path: '/tool', name: 'Tool', component: ()=>import('@views/components/Tool.vue') }
|
路由设置hash模式
1 2 3 4 5 6 7 8
| import { createRouter, createWebHashHistory } from 'vue-router' import routes from './routes' const router = createRouter({ history: createWebHashHistory(), routes })
export default router
|
loadURL改为loadFile
判断是否是开发环境
- process.env.NODE_ENV === ‘development’
- ELECTRON_RENDERER_URL 如果没有设置,在生产环境中默认undefined
1 2 3 4 5 6 7
| if(process.env['ELECTRON_RENDERER_URL']) { toolWindow.loadURL(process.env['ELECTRON_RENDERER_URL']+'/#/tool') } else { toolWindow.loadFile(path.join(__dirname, '../renderer/index.html'), {hash:'/tool'}) }
|
如何实现数据共享
问题描述:使用electron开发桌面应用,如何实现不同窗口之间的数据共享?
原因
在electron中不同的窗口之间默认有数据隔离,导致不同窗口之间无法共享数据。
解决方案
跨窗口通信
流程:窗口b渲染进程向主进程通信,主进程向窗口a渲染进程通信。
窗口b渲染进程
1 2 3 4 5 6 7 8 9 10
| const { ipcRenderer } = require('electron'); const saveConfiguration = () => { const config = JSON.stringify(form.value) try { ipcRenderer.send('renderer-to-main', { config, name: 'saveConfig' }); } catch (error) { console.error('发送 IPC 消息失败:', error); } ElMessage.success('配置保存成功') }
|
主进程监听窗口b渲染进程
1 2 3 4 5 6
| const { ipcMain } = require('electron'); ipcMain.on('renderer-to-main', (event, { name, data }) => { const config = JSON.parse(data.config) mainWindow.webContents.send('main-to-renderer', { config }) })
|
窗口a监听主进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| const { ipcRenderer } = require('electron'); ipcRenderer.on('main-to-renderer', (event, { config }) => { store.saveConfig(data.config) })
import { createPinia, defineStore } from 'pinia' const pinia = createPinia()
export const useStore = defineStore('main', { state: () => ({ config: JSON.parse(localStorage.getItem('config') || '{}') }), actions: { saveConfig(config) { this.config = config localStorage.setItem('config', JSON.stringify(config)) }, } })
export default pinia
|
Electron Store
描述:可以使用 Electron Store 或 SQLite 等持久化数据库来共享数据。主进程负责对存储的数据进行写入和读取,各个窗口通过 IPC 请求主进程获取或更新数据。这种方法的优点是数据可以持久化,窗口关闭后不会丢失。
注意:
- Electron Store 仅支持 Node.js 环境,不能在渲染进程中使用。
- 需要 Electron 30 或更高版本。
安装:
1
| npm install --save electron-store
|
主进程
1 2 3 4 5 6 7 8 9 10 11
| const Store = require('electron-store') const store = new Store()
ipcMain.on('save-data', (event, data) => { store.set('sharedData', data) })
ipcMain.handle('get-data', () => { return store.get('sharedData') })
|
窗口渲染进程
1 2 3 4 5 6
| ipcRenderer.invoke('get-data').then((data) => { console.log(data) })
ipcRenderer.send('save-data', { name: 'John', age: 30 })
|
禁用数据隔离
创建窗口时,lectron 提供了 webPreferences 中的 partition 和 session 选项来控制浏览器会话和数据隔离。如果你不进行特别的配置,默认情况下,所有窗口都会共享同一个 session
例如:
- Cookies
- IndexedDB索引数据库
- localStorage 本地存储
示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| const { BrowserWindow } = require('electron')
const mainWindow = new BrowserWindow({ webPreferences: { partition: 'persist:shared', } })
const anotherWindow = new BrowserWindow({ webPreferences: { partition: 'persist:shared', } })
|
渲染进程
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| function saveData() { const inputData = document.getElementById('inputData').value localStorage.setItem('sharedData', inputData) console.log('Data saved:', inputData) }
function printData() { const storedData = localStorage.getItem('sharedData') console.log('Stored Data:', storedData) }
window.addEventListener('storage', (event) => { if (event.key === 'sharedData') { console.log('Shared data updated:', event.newValue) } })
|
将 partition 设置为 'persist:shared',确保 窗口 A 和 B 使用相同的会话存储。任何在 localStorage 或 Cookies 中的数据都将在这两个窗口之间共享。persist:shared 是持久会话,因此即使窗口关闭,数据也会被保留。
注意事项
进程隔离:即使共享了 localStorage 和 session,不同窗口的 渲染进程还是相互隔离的,因此 JavaScript 变量或 Vuex/Pinia 的状态等不会共享。
同步问题:即便是共享的 localStorage,其变更不会自动在多个窗口之间同步。如果一个窗口更新了 localStorage 数据,其他窗口不会自动得到通知。要实现数据的实时同步,仍然需要借助 IPC 通信 或 storage 事件监听。
持久化会话名称:当 partition 前缀为 persist: 时,会话数据会持久化存储(即使应用关闭也会保留)。如果没有 persist:,则是临时的,窗口关闭后数据将清空。
示例:实现共享和实时更新
通过 partition 配置共享 localStorage 后,还可以监听 storage 事件来确保实时同步。例如:
1 2 3 4 5
| window.addEventListener('storage', (event) => { console.log('Storage changed:', event.key, event.newValue) })
|
总结
- 配置相同的 partition 可以共享 localStorage 和 session。
- 实时同步 仍然建议使用 storage 事件监听或 IPC。
- 持久化和隔离控制:persist: 前缀确保数据在应用关闭后保留。