# 自定义 StorageDriver
本文档提供了关于如何自定义 StorageDriver 的开发指南,以及相关的 API 信息和示例代码。
# 概述
StorageDriver 是一个用于存储和管理数据的接口。它只关心数据应如何被存储、删除以及管理分区等功能。通过自定义 StorageDriver,您可以实现对数据的读取、写入、删除等操作,并可以监听数据的变化。
# API 参考
# StorageContext 类
class StorageContext {
public id: string;
public feature: string;
}
StorageContext 类表示存储上下文,用于标识存储的数据和特性。
# PDFViewerStorageContext 类
class PDFViewerStorageContext extends StorageContext {
public pdfViewer: PDFViewer;
}
PDFViewerStorageContext 类继承自 StorageContext 类,表示 PDFViewer 的存储上下文。它包含了一个 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 实例,用于存储和管理数据。应用层将自定义的 StorageDriver 实例通过 custom.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 这些方法来自定义自己的 StorageDriver。
- getAll(context: StorageContext): Promise<Record<string, any>>:获取指定上下文中的所有数据。
- get
(context: StorageContext, key: string): Promise<T | null>:获取指定上下文中指定键的数据。 - set
(context: StorageContext, key: string, value: T): Promise :设置指定上下文中指定键的数据。 - removeAll(context: StorageContext): Promise
:移除指定上下文中的所有数据。 - remove(context: StorageContext, key: string): Promise
:移除指定上下文中指定键的数据。 - onChange
(callback: (event: StorageDriverChangeEvent ) => 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 实例来存储和管理数据。
← PDFViewer 多实例 入门指南 →