# 自定义 StorageDriver
本节将介绍如何自定义 StorageDriver,以及相关的 API 信息和示例代码。
# 概述
StorageDriver 是一个用于存储和管理数据的接口,主要关注数据的存储、删除和管理分区方式。通过自定义 StorageDriver,您可以实现数据的读取、写入、删除等操作,并监控数据的变化。
# API Reference
# StorageContext
类
class StorageContext {
public id: string;
public feature: string;
}
StorageContext
类表示存储上下文,用于标识存储的数据和特性。
# PDFViewerStorageContext
类
class PDFViewerStorageContext extends StorageContext {
public pdfViewer: PDFViewer;
}
PDFViewerStorageContext
类继承自 StorageContext
类,表示 PDFViewer
的存储上下文。它包含了一个 PDFViewer
实例,通过该实例,可以获得当前文档和当前页等信息。通过合理地组合这些信息,可以对数据进行分区存储。
# PDFViewer
接口
interface PDFViewer {
getInstanceId(): string;
}
从 9.1.0 版本开始,PDFViewer
接口新增了一个方法 getInstanceId()
,该方法用于获取 PDFViewer
的实例 ID。当存在多个 PDFViewer
实例时,请确保它们的 ID 是唯一的,以便对不同 PDFViewer
实例的数据进行分区存储。
# PDFViewerConstructor
接口
interface PDFViewerConstructor {
new(options: {
instanceId: string,
customs: {
storageDriver: StorageDriver;
}
}): PDFViewer;
}
PDFViewerConstructor
接口用于描述创建 PDFViewer
实例的构造函数信息。从 9.1.0 版本开始,该构造函数增加了一个包含 instanceId
和 customs
属性的 options
对象作为参数。其中 customs
属性包含了一个 StorageDriver
实例,用于存储和管理数据。为了实现自定义存储功能,应用层可以通过 custom.storageDriver
将自定义的 StorageDriver
实例传递给 PDFViewer
。
# StorageDriver
接口
interface StorageDriver {
public getAll(context: StorageContext): Promise<Record<string, any>>;
public get<T>(context: StorageContext, key: string): Promise<T | null>;
public set<T>(context: StorageContext, key: string, value: T): Promise<void>;
public removeAll(context: StorageContext): Promise<void>;
public remove(context: StorageContext, key: string): Promise<void>;
public onChange<T>(callback: (event: StorageDriverChangeEvent<T>) => void): Function;
public onRemove(callback: (event: StorageDriverRemoveEvent) => void): Function;
}
StorageDriver
是一个定义了一组用于存储和管理数据方法的接口。您可以通过实现这些方法来实现自定义的 StorageDriver
。
getAll(context: StorageContext): Promise<Record<string, any>>
: 获取指定上下文中的所有数据。get<T>(context: StorageContext, key: string): Promise<T | null>
: 获取指定上下文中指定键的数据。set<T>(context: StorageContext, key: string, value: T): Promise<void>
: 设置指定上下文中指定键的数据。removeAll(context: StorageContext): Promise<void>
: 移除指定上下文中的所有数据。remove(context: StorageContext, key: string): Promise<void>
: 移除指定上下文中指定键的数据。onChange<T>(callback: (event: StorageDriverChangeEvent<T>) => void): Function
: 注册监听数据变化的回调函数。onRemove(callback: (event: StorageDriverRemoveEvent) => void): Function
: 注册监听数据移除的回调函数。
# StorageDriverChangeEvent
接口
interface StorageDriverChangeEvent<T> {
public context: StorageContext;
public key: string;
public oldValue: T;
public newValue: T;
}
StorageDriverChangeEvent
接口表示数据变化的事件对象。它包含了上下文、键、旧值和新值等信息,在数据变化发生后,回调函数可以接收到该对象。
# StorageDriverRemoveEvent
接口
interface StorageDriverRemoveEvent {
public context: StorageContext;
public key: string;
}
StorageDriverRemoveEvent
接口表示数据移除的事件对象。它包含了上下文和键等信息, 在数据移除事件发生后,回调函数可以接收到该对象。
# 自定义 StorageDriver
要自定义 StorageDriver
,您需要创建一个实现 StorageDriver
接口的子类,并实现其中的方法。
下面是一个基于 sessionStorage
(opens new window) 实现的自定义 StorageDriver
的示例:
class MyStorageDriver extends StorageDriver {
// 使用第三方库: https://www.npmjs.com/package/eventemitter3 实现事件分发
private readonly eventEmitter = new EventEmitter();
// 根据上下文信息生成一个存储空间名称,主要作用是对数据进行分区存储
private getSpace(context: StorageContext): string {
const instanceId = context.id;
return [instanceId, context.feature].join('.');
}
async getAll(context: StorageContext): Promise<Record<string, any>> {
const space = this.getSpace(context);
const keys = this.getSpaceKeys(context);
return keys.reduce((result, completeKey) => {
const key = completeKey.slice(space.length + 1);
const rawData = sessionStorage.getItem(completeKey);
result[key] = rawData ? JSON.parse(rawData) : null;
return result;
}, {});
}
async get<T>(context: StorageContext, key: string): Promise<T | null> {
const storageKey = this.generateUniqueKey(context, key);
const valueStr = sessionStorage.getItem(storageKey);
if (valueStr) {
return JSON.parse(valueStr) as T;
} else {
return null as T;
}
}
async set<T>(context: StorageContext, key: string, value: T): Promise<void> {
const storageKey = this.generateUniqueKey(context, key);
const oldValueJSON = sessionStorage.getItem(storageKey);
const oldValue = oldValueJSON ? JSON.parse(oldValueJSON) : undefined;
const newValue = JSON.stringify(value);
if (oldValueJSON === newValue) {
return;
}
sessionStorage.setItem(storageKey, newValue);
this.emitChangeEvent({
context,
key,
oldValue,
newValue: value
});
}
async removeAll(context: StorageContext): Promise<void> {
const keys = this.getSpaceKeys(context);
keys.forEach(key => {
const oldValue = sessionStorage.getItem(key);
sessionStorage.removeItem(key);
const newValue = sessionStorage.getItem(key);
if (newValue !== oldValue) {
this.emitRemoveEvent({
context,
key
} as StorageDriverRemoveEvent);
}
});
}
async remove(context: StorageContext, key: string): Promise<void> {
const storageKey = this.generateUniqueKey(context, key);
const oldValue = sessionStorage.getItem(storageKey);
sessionStorage.removeItem(storageKey);
const newValue =
sessionStorage.getItem(storageKey);
if (newValue !== oldValue) {
this.emitRemoveEvent({
context,
key
});
}
}
onChange<T>(callback: (event: StorageDriverChangeEvent<T>) => void): () => void {
return this.addEventListener<T>('change', callback);
}
onRemove(callback: (event: StorageDriverRemoveEvent) => void): () => void {
return this.addEventListener('remove', callback);
}
private addEventListener<T>(event: 'change' | 'remove', callback: (event: any) => void) {
const listener = e => {
callback(e);
};
this.eventEmitter.addListener(event, listener);
return () => {
this.eventEmitter.removeListener(event, listener);
};
}
// 根据 namespace 和 key 生成一个唯一的索引值
private generateUniqueKey(context: StorageContext, key: string) {
const space = this.getSpace(context);
return [space, key].join('.');
}
// 获取命名空间下所有存储的键值对
private getSpaceKeys(context: StorageContext): string[] {
const space = this.getSpace(context);
const prefix = space + '.';
return Array(sessionStorage.length)
.fill(0)
.map((_, index) => sessionStorage.key(index))
.filter(it => !!it)
.filter(it => it!.indexOf(prefix) === 0) as string[];
}
// 数据变更时,触发数据变更事件
private emitChangeEvent<T>(event: StorageDriverChangeEvent<T>) {
this.eventEmitter.emit('change', event);
}
// 数据被删除时,触发数据删除事件
private emitRemoveEvent<T>(event: StorageDriverRemoveEvent) {
this.eventEmitter.emit('remove', event);
}
}
您可以根据实际需求,实现自定义 StorageDriver
。在实现过程中,可以使用异步操作、数据库查询等技术来实现数据的存储和管理。
# 使用自定义 StorageDriver
要使用自定义的 StorageDriver
,您需要创建一个 PDFViewer
实例,并将自定义的 StorageDriver
作为参数传递给构造函数。
下面是一个使用自定义 StorageDriver
的示例:
const storageDriver = new MyStorageDriver();
const pdfViewer = new PDFViewer({
instanceId: 'pdf-viewer-1',
customs: {
storageDriver: storageDriver
}
});
在创建 PDFViewer
实例时,将自定义的 StorageDriver
传递给 customs
属性。PDFViewer 将使用该 StorageDriver
实例来存储和管理数据。