From 5d7dc2fd65847ddf8e641ebcccb9e89263fa5383 Mon Sep 17 00:00:00 2001 From: "mario.gk" Date: Mon, 22 Jun 2020 22:23:13 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E6=94=AF=E6=8C=81=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=E5=9B=9E=E6=BB=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/src/document/document-model.ts | 46 +++++++++- packages/designer/src/document/node/node.ts | 2 + packages/designer/src/project/project.ts | 4 +- packages/editor-preset-vision/src/pages.ts | 12 +++ .../src/rootNodeVisitor.ts | 91 +++++++++++++++++++ 5 files changed, 151 insertions(+), 4 deletions(-) create mode 100644 packages/editor-preset-vision/src/rootNodeVisitor.ts diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 2a091d293..aad2e757e 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -27,7 +27,7 @@ export class DocumentModel { /** * 文档编号 */ - readonly id: string = uniqueId('doc'); + id: string = uniqueId('doc'); /** * 选区控制 */ @@ -42,6 +42,7 @@ export class DocumentModel { private seqId = 0; private _simulator?: ISimulatorHost; private emitter: EventEmitter; + private rootNodeVisitorMap: { [visitorName: string]: any } = {}; /** * 模拟器 @@ -197,9 +198,14 @@ export class DocumentModel { this.nodesMap.set(node.id, node); this.nodes.add(node); + this.emitter.emit('nodecreate', node); return node as any; } + public destroyNode(node: Node) { + this.emitter.emit('nodedestroy', node); + } + /** * 插入一个节点 */ @@ -409,7 +415,7 @@ export class DocumentModel { /** * 打开,已载入,默认建立时就打开状态,除非手动关闭 */ - open(): void { + open(): DocumentModel { const originState = this._opened; this._opened = true; if (originState === false) { @@ -420,6 +426,7 @@ export class DocumentModel { } else { this.project.checkExclusive(this); } + return this; } /** @@ -513,6 +520,41 @@ export class DocumentModel { setRendererReady(renderer) { this.emitter.emit('lowcode_engine_renderer_ready', renderer); } + + acceptRootNodeVisitor( + visitorName: string = 'default', + visitorFn: (node: RootNode) => any ) { + let visitorResult = {}; + if (!visitorName) { + /* tslint:disable no-console */ + console.warn('Invalid or empty RootNodeVisitor name.'); + } + try { + visitorResult = visitorFn.call(this, this.rootNode); + this.rootNodeVisitorMap[visitorName] = visitorResult; + } catch (e) { + console.error('RootNodeVisitor is not valid.'); + } + return visitorResult; + } + + getRootNodeVisitor(name: string) { + return this.rootNodeVisitorMap[name]; + } + + onNodeCreate(func: (node: Node) => void) { + this.emitter.on('nodecreate', func); + return () => { + this.emitter.removeListener('nodecreate', func); + }; + } + + onNodeDestroy(func: (node: Node) => void) { + this.emitter.on('nodedestroy', func); + return () => { + this.emitter.removeListener('nodedestroy', func); + }; + } } export function isDocumentModel(obj: any): obj is DocumentModel { diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index 9dd21f6f8..1061d3f1d 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -633,6 +633,8 @@ export class Node { this.autoruns?.forEach((dispose) => dispose()); this.props.purge(); this.document.internalRemoveAndPurgeNode(this); + + this.document.destroyNode(this); } // ======= compatible apis ==== diff --git a/packages/designer/src/project/project.ts b/packages/designer/src/project/project.ts index 8217697be..e010c5476 100644 --- a/packages/designer/src/project/project.ts +++ b/packages/designer/src/project/project.ts @@ -122,7 +122,7 @@ export class Project { if (data) { doc = new DocumentModel(this, data); this.documents.push(doc); - doc.open(); + return doc.open(); } return; @@ -134,7 +134,7 @@ export class Project { doc = new DocumentModel(this, doc); this.documents.push(doc); - doc.open(); + return doc.open(); } checkExclusive(actived: DocumentModel) { diff --git a/packages/editor-preset-vision/src/pages.ts b/packages/editor-preset-vision/src/pages.ts index 23ad9fe23..bc3ee9d12 100644 --- a/packages/editor-preset-vision/src/pages.ts +++ b/packages/editor-preset-vision/src/pages.ts @@ -1,6 +1,7 @@ import { designer } from './editor'; import { RootSchema } from '@ali/lowcode-types'; import { DocumentModel } from '@ali/lowcode-designer'; +import NodeCacheVisitor from './rootNodeVisitor'; const { project } = designer; @@ -96,4 +97,15 @@ Object.defineProperty(pages, 'currentPage', { } }) +pages.onCurrentPageChange((page: DocumentModel) => { + if (!page) { return; } + page.acceptRootNodeVisitor('NodeCache', (rootNode) => { + const visitor: NodeCacheVisitor = page.getRootNodeVisitor('NodeCache'); + if (visitor) { + visitor.destroy(); + } + return new NodeCacheVisitor(page, rootNode); + }); +}); + export default pages; diff --git a/packages/editor-preset-vision/src/rootNodeVisitor.ts b/packages/editor-preset-vision/src/rootNodeVisitor.ts new file mode 100644 index 000000000..811aa5fd7 --- /dev/null +++ b/packages/editor-preset-vision/src/rootNodeVisitor.ts @@ -0,0 +1,91 @@ +import { findIndex } from 'lodash'; +import { DocumentModel, Node, Root } from '@ali/lowcode-designer'; + +/** + * RootNodeVisitor for VisualEngine Page + * + * - store / cache node + * - quickly find / search or do operations on Node + */ +export default class RootNodeVisitor { + public nodeIdMap: {[id: string]: Node} = {}; + public nodeFieldIdMap: {[fieldId: string]: Node} = {}; + public nodeList: Node[] = []; + + private page: DocumentModel; + private root: RootNode; + private cancelers: Function[] = []; + + constructor(page: DocumentModel, rootNode: RootNode) { + this.page = page; + this.root = rootNode; + + this._findNode(this.root); + this._init(); + } + + public getNodeList() { + return this.nodeList; + } + + public getNodeIdMap() { + return this.nodeIdMap; + } + + public getNodeFieldIdMap() { + return this.nodeFieldIdMap; + } + + public getNodeById(id?: string) { + if (!id) { return this.nodeIdMap; } + return this.nodeIdMap[id]; + } + + public getNodeByFieldId(fieldId?: string) { + if (!fieldId) { return this.nodeFieldIdMap; } + return this.nodeFieldIdMap[fieldId]; + } + + public destroy() { + this.cancelers.forEach((canceler) => canceler()); + } + + private _init() { + this.cancelers.push( + this.page.onNodeCreate((node) => { + this.nodeList.push(node); + this.nodeIdMap[node.id] = node; + if (node.getPropValue('fieldId')) { + this.nodeFieldIdMap[node.getPropValue('fieldId')] = node; + } + }), + ); + + this.cancelers.push( + this.page.onNodeDestroy((node) => { + const idx = findIndex(this.nodeList, (n) => node.id === n.id); + this.nodeList.splice(idx, 1); + delete this.nodeIdMap[node.id]; + if (node.getPropValue('fieldId')) { + delete this.nodeFieldIdMap[node.getPropValue('fieldId')]; + } + }), + ); + } + + private _findNode(node: Node) { + const props = node.getProps(); + const fieldId = props && props.getPropValue('fieldId'); + + this.nodeIdMap[node.getId()] = node; + this.nodeList.push(node); + if (fieldId) { + this.nodeFieldIdMap[fieldId] = node; + } + + const children = node.getChildren(); + if (children) { + children.forEach((child) => this._findNode(child)); + } + } +}