mirror of
https://github.com/Tencent/tmagic-editor.git
synced 2025-06-14 17:06:03 +08:00
feat(editor): 完善storageService功能
新增namespace,setItem/getItem时自动key自动加上namespace;setItem可以指定协议;getItem时根据协议自动解析 fix #224
This commit is contained in:
parent
6e199897ac
commit
574e03f685
@ -18,7 +18,6 @@
|
||||
|
||||
import { reactive, toRaw } from 'vue';
|
||||
import { cloneDeep, mergeWith, uniq } from 'lodash-es';
|
||||
import serialize from 'serialize-javascript';
|
||||
|
||||
import type { Id, MApp, MComponent, MContainer, MNode, MPage } from '@tmagic/schema';
|
||||
import { NodeType } from '@tmagic/schema';
|
||||
@ -26,7 +25,7 @@ import StageCore from '@tmagic/stage';
|
||||
import { getNodePath, isNumber, isPage, isPop } from '@tmagic/utils';
|
||||
|
||||
import historyService, { StepValue } from '@editor/services/history';
|
||||
import storageService from '@editor/services/storage';
|
||||
import storageService, { Protocol } from '@editor/services/storage';
|
||||
import type { AddMNode, EditorNodeInfo, PastePosition, StoreState } from '@editor/type';
|
||||
import { LayerOffset, Layout } from '@editor/type';
|
||||
import {
|
||||
@ -483,7 +482,9 @@ class Editor extends BaseService {
|
||||
* @returns 组件节点配置
|
||||
*/
|
||||
public async copy(config: MNode | MNode[]): Promise<void> {
|
||||
await storageService.setItem(COPY_STORAGE_KEY, serialize(Array.isArray(config) ? config : [config]));
|
||||
await storageService.setItem(COPY_STORAGE_KEY, Array.isArray(config) ? config : [config], {
|
||||
protocol: Protocol.OBJECT,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@ -492,19 +493,10 @@ class Editor extends BaseService {
|
||||
* @returns 添加后的组件节点配置
|
||||
*/
|
||||
public async paste(position: PastePosition = {}): Promise<MNode[] | void> {
|
||||
const configStr = await storageService.getItem(COPY_STORAGE_KEY);
|
||||
// eslint-disable-next-line prefer-const
|
||||
let config: any = {};
|
||||
if (!configStr) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
// eslint-disable-next-line no-eval
|
||||
eval(`config = ${configStr}`);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
return;
|
||||
}
|
||||
const config = await storageService.getItem(COPY_STORAGE_KEY);
|
||||
|
||||
if (!config) return;
|
||||
|
||||
const pasteConfigs = await beforePaste(position, config);
|
||||
|
||||
return await this.multiAdd(pasteConfigs);
|
||||
|
@ -1,39 +1,80 @@
|
||||
import serialize from 'serialize-javascript';
|
||||
|
||||
import BaseService from './BaseService';
|
||||
|
||||
interface Options {
|
||||
namespace?: string;
|
||||
protocol?: Protocol;
|
||||
}
|
||||
|
||||
export enum Protocol {
|
||||
OBJECT = 'object',
|
||||
JSON = 'json',
|
||||
STRING = 'string',
|
||||
NUMBER = 'number',
|
||||
BOOLEAN = 'boolean',
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据存储服务
|
||||
*/
|
||||
export class WebStorage extends BaseService {
|
||||
private storage: Storage = globalThis.localStorage;
|
||||
private namespace = 'tmagic';
|
||||
|
||||
constructor() {
|
||||
super(['getStorage', 'clear', 'getItem', 'removeItem', 'setItem']);
|
||||
super(['getStorage', 'getNamespace', 'clear', 'getItem', 'removeItem', 'setItem']);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取数据存储对象,可以通过
|
||||
* const storageService = new StorageService();
|
||||
* storageService.use({
|
||||
* storageService.usePlugin({
|
||||
* // 替换存储对象为 sessionStorage
|
||||
* async getStorage(): Promise<Storage> {
|
||||
* return window.sessionStorage;
|
||||
* async afterGetStorage(): Promise<Storage> {
|
||||
* return window.sessionStorage;
|
||||
* },
|
||||
* });
|
||||
*/
|
||||
public async getStorage(): Promise<Storage> {
|
||||
return globalThis.localStorage;
|
||||
return this.storage;
|
||||
}
|
||||
|
||||
public async getNamespace(): Promise<string> {
|
||||
return this.namespace;
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理,支持storageService.use
|
||||
* 清理,支持storageService.usePlugin
|
||||
*/
|
||||
public async clear(): Promise<void> {
|
||||
const storage = await this.getStorage();
|
||||
storage.clear();
|
||||
}
|
||||
/**
|
||||
* 获取存储项,支持storageService.use
|
||||
* 获取存储项,支持storageService.usePlugin
|
||||
*/
|
||||
public async getItem(key: string): Promise<string | null> {
|
||||
const storage = await this.getStorage();
|
||||
return storage.getItem(key);
|
||||
public async getItem(key: string, options: Options = {}): Promise<any> {
|
||||
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||
const { protocol = options.protocol, item } = this.getValueAndProtocol(
|
||||
storage.getItem(`${options.namespace || namespace}:${key}`),
|
||||
);
|
||||
|
||||
if (item === null) return null;
|
||||
|
||||
switch (protocol) {
|
||||
case Protocol.OBJECT:
|
||||
// eslint-disable-next-line no-eval
|
||||
return eval(`(${item})`);
|
||||
case Protocol.JSON:
|
||||
return JSON.parse(item);
|
||||
case Protocol.NUMBER:
|
||||
return Number(item);
|
||||
case Protocol.BOOLEAN:
|
||||
return Boolean(item);
|
||||
default:
|
||||
return item;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 获取指定索引位置的key
|
||||
@ -42,20 +83,51 @@ export class WebStorage extends BaseService {
|
||||
const storage = await this.getStorage();
|
||||
return storage.key(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除存储项,支持storageService.use
|
||||
* 移除存储项,支持storageService.usePlugin
|
||||
*/
|
||||
public async removeItem(key: string): Promise<void> {
|
||||
const storage = await this.getStorage();
|
||||
storage.removeItem(key);
|
||||
public async removeItem(key: string, options: Options = {}): Promise<void> {
|
||||
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||
storage.removeItem(`${options.namespace || namespace}:${key}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置存储项,支持storageService.use
|
||||
* 设置存储项,支持storageService.usePlugin
|
||||
*/
|
||||
public async setItem(key: string, value: string): Promise<void> {
|
||||
const storage = await this.getStorage();
|
||||
storage.setItem(key, value);
|
||||
public async setItem(key: string, value: any, options: Options = {}): Promise<void> {
|
||||
const [storage, namespace] = await Promise.all([this.getStorage(), this.getNamespace()]);
|
||||
let item = value;
|
||||
const protocol = options.protocol ? `${options.protocol}:` : '';
|
||||
if (typeof value === Protocol.STRING || typeof value === Protocol.NUMBER) {
|
||||
item = `${protocol}${value}`;
|
||||
} else {
|
||||
item = `${protocol}${serialize(value)}`;
|
||||
}
|
||||
storage.setItem(`${options.namespace || namespace}:${key}`, item);
|
||||
}
|
||||
|
||||
private getValueAndProtocol(value: string | null) {
|
||||
let protocol = '';
|
||||
|
||||
if (value === null) {
|
||||
return {
|
||||
item: value,
|
||||
protocol,
|
||||
};
|
||||
}
|
||||
|
||||
const item = value.replace(new RegExp(`^(${Object.values(Protocol).join('|')})(:)(.+)`), (_$0, $1, _$2, $3) => {
|
||||
protocol = $1;
|
||||
return $3;
|
||||
});
|
||||
|
||||
return {
|
||||
protocol,
|
||||
item,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type StorageService = WebStorage;
|
||||
export default new WebStorage();
|
||||
|
@ -354,7 +354,7 @@ describe('copy', () => {
|
||||
const node = editorService.getNodeById(NodeId.NODE_ID2);
|
||||
await editorService.copy(node!);
|
||||
const str = await storageService.getItem(COPY_STORAGE_KEY);
|
||||
expect(str).toBe(JSON.stringify([node]));
|
||||
expect(str).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
@ -372,7 +372,7 @@ describe('paste', () => {
|
||||
});
|
||||
|
||||
test('空', async () => {
|
||||
globalThis.localStorage.clear();
|
||||
await storageService.clear();
|
||||
const newNode = await editorService.paste({ left: 0, top: 0 });
|
||||
expect(newNode).toBeUndefined();
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user