本文最后更新于:2021年3月2日 凌晨
场景
有时候我们需要在主进程和渲染层共享某些数据,而 electron ipc 通信 显然更适合传递消息而不适合共享数据。
相关依赖
事实上,我们这个需求已经有人考虑过了,例如 electron-store 就已经实现了可以在渲染层、主进程均可使用。
那么,我们直接用 electron-store 有什么问题么?
是的,electron 仅能在 electron 中使用,所以在浏览器上会报错,而这对于开发环境而言是无法接受的,故而还需要检测环境使用不同的实现。
创建浏览器兼容层
使用策略模式实现不同环境下使用不同的存储
- 浏览器使用 localStorage 实现
- electron 中则使用 electron-store 实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
| import type Store from 'electron-store' import isElectron from 'is-electron' import { DeepReadonly } from 'utility-types'
interface BaseStore { get(key: string): string | null
set(key: string, value: string): void }
class ElectronStoreImpl implements BaseStore { private store: Store
constructor() { const Store = window.require('electron-store') this.store = new Store() }
set(key: string, value: string): void { this.store.set(key, value) }
get(key: string) { return this.store.get(key) as string } }
class LocalStorageImpl implements BaseStore { get(key: string) { return localStorage.getItem(key) }
set(key: string, value: string) { localStorage.setItem(key, value) } }
const symbol = Symbol('ElectronStore.store')
export class ElectronStore { private readonly [symbol]: BaseStore = isElectron() ? new ElectronStoreImpl() : new LocalStorageImpl()
static getInstance<T extends object>( init?: Partial<T>, ): Partial<{ [P in keyof T]: DeepReadonly<T[P]> }> { const electronStore = new ElectronStore()
const proxy = new Proxy({} as any, { get(target: any, p: string): any { const text = electronStore[symbol].get(p) try { if (text === null || text === undefined) { return null } return JSON.parse(text) } catch (e) { return null } }, set(target: any, p: string, value: any): boolean { electronStore[symbol].set( p, value !== undefined && value !== null ? JSON.stringify(value) : value, ) return true }, }) if (init) { Object.entries(init).forEach(([k, v]) => { const text = electronStore[symbol].get(k) if (text === null || text === undefined) { proxy[k] = v } }) } return proxy } }
|
你可能发现了,为了简化使用的 API,这里使用了代理模式拦截了对实例的访问,修改为使用 get/set
方法取值和设值。
使用
使用起来和一个普通的对象没什么区别,直接通过 .
访问或设置属性即可。
1 2 3 4 5
| const userStore = ElectronStore.getInstance<{ name: string; age: number }>() userStore.name = 'liuli' console.log(userStore.name === 'liuli') userStore.age = 1 console.log(userStore.age === 1)
|
具体代码在 electron_example,由于是一个浅层封装,所以并未发布,但可以直接将模块复制到项目中使用。