From 0461a57d577f86c77dbbe076779ab2598feed220 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8A=9B=E7=9A=93?= Date: Wed, 2 Sep 2020 13:46:42 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=87=8D=E6=96=B0=E6=A2=B3?= =?UTF-8?q?=E7=90=86=20purge=20/=20remove=20/=20delete=20=E7=9A=84?= =?UTF-8?q?=E8=81=8C=E8=B4=A3=EF=BC=8C=E4=BB=A5=E5=8F=8A=E7=9B=B8=E5=BA=94?= =?UTF-8?q?=E9=87=8D=E6=9E=84=20refactor:=20=E8=B0=83=E6=95=B4=E5=88=A4?= =?UTF-8?q?=E6=96=AD=20fieldId=20=E6=98=AF=E5=90=A6=E5=AD=98=E5=9C=A8?= =?UTF-8?q?=E7=9A=84=E9=80=BB=E8=BE=91=20fix:=20=E8=A7=A3=E5=86=B3=20redo?= =?UTF-8?q?=20=E6=97=B6=E9=A1=B5=E9=9D=A2=E8=8A=82=E7=82=B9=E6=95=B0?= =?UTF-8?q?=E4=B8=8D=E5=AF=B9=E4=BB=A5=E5=8F=8A=20fieldId=20=E8=A2=AB?= =?UTF-8?q?=E9=87=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../designer/src/document/document-model.ts | 18 +++--- .../src/document/node/node-children.ts | 58 +++++++++++------- packages/designer/src/document/node/node.ts | 37 ++++------- .../designer/src/document/node/props/prop.ts | 61 ++++++++++--------- .../designer/src/document/node/props/props.ts | 4 +- packages/editor-preset-vision/src/editor.ts | 37 +++++------ 6 files changed, 107 insertions(+), 108 deletions(-) diff --git a/packages/designer/src/document/document-model.ts b/packages/designer/src/document/document-model.ts index 7a7666d63..58d17a67f 100644 --- a/packages/designer/src/document/document-model.ts +++ b/packages/designer/src/document/document-model.ts @@ -267,14 +267,16 @@ export class DocumentModel { /** * 内部方法,请勿调用 */ - internalRemoveAndPurgeNode(node: Node) { + internalRemoveAndPurgeNode(node: Node, useMutator = false) { if (!this.nodes.has(node)) { return; } - this._nodesMap.delete(node.id); + node.remove(useMutator); + } + + unlinkNode(node: Node) { this.nodes.delete(node); - this.selection.remove(node.id); - node.remove(); + this._nodesMap.delete(node.id); } @obx.ref private _dropLocation: DropLocation | null = null; @@ -318,20 +320,20 @@ export class DocumentModel { * 导出 schema 数据 */ get schema(): RootSchema { - return this.rootNode.schema as any; + return this.rootNode?.schema as any; } import(schema: RootSchema, checkId = false) { - // TODO: do purge this.nodes.forEach(node => { + this.internalRemoveAndPurgeNode(node, true); this.destroyNode(node); }); - this.rootNode.import(schema as any, checkId); + this.rootNode?.import(schema as any, checkId); // todo: select added and active track added } export(stage: TransformStage = TransformStage.Serilize) { - return this.rootNode.export(stage); + return this.rootNode?.export(stage); } /** diff --git a/packages/designer/src/document/node/node-children.ts b/packages/designer/src/document/node/node-children.ts index f89e55008..7fe20ef65 100644 --- a/packages/designer/src/document/node/node-children.ts +++ b/packages/designer/src/document/node/node-children.ts @@ -15,7 +15,7 @@ export class NodeChildren { }); } - interalInitParent() { + internalInitParent() { this.children.forEach(child => child.internalSetParent(this.owner)); } @@ -55,7 +55,7 @@ export class NodeChildren { } this.children = children; - this.interalInitParent(); + this.internalInitParent(); if (!shallowEqual(children, originChildren)) { this.emitter.emit('change'); } @@ -63,7 +63,7 @@ export class NodeChildren { /** * @deprecated - * @param nodes + * @param nodes */ concat(nodes: Node[]) { return this.children.concat(nodes); @@ -91,20 +91,46 @@ export class NodeChildren { return this.children.length; } + private purged = false; + /** + * 回收销毁 + */ + purge(useMutator = true) { + if (this.purged) { + return; + } + this.purged = true; + this.children.forEach((child) => { + child.purge(useMutator); + }); + } + /** * 删除一个节点 */ delete(node: Node, purge = false, useMutator = true): boolean { + if (node.isParental()) { + node.children.forEach(subNode => { + subNode.remove(useMutator, purge); + }); + } + if (purge) { + // should set parent null + node.internalSetParent(null, useMutator); + try { + node.purge(useMutator); + } catch(err) { + console.error(err); + } + } const i = this.children.indexOf(node); if (i < 0) { return false; } - const deleted = this.children.splice(i, 1)[0]; - if (purge) { - // should set parent null - deleted.internalSetParent(null, useMutator); - deleted.purge(useMutator); - } + this.children.splice(i, 1); + const document = node.document; + document.unlinkNode(node); + document.selection.remove(node.id); this.emitter.emit('change'); if (useMutator) { this.reportModified(node, this.owner, {type: 'remove', removeIndex: i, removeNode: node}); @@ -290,18 +316,6 @@ export class NodeChildren { }; } - private purged = false; - /** - * 回收销毁 - */ - purge(useMutator = true) { - if (this.purged) { - return; - } - this.purged = true; - this.children.forEach((child) => child.purge(useMutator)); - } - get [Symbol.toStringTag]() { // 保证向前兼容性 return 'Array'; @@ -327,7 +341,7 @@ export class NodeChildren { try { callbacks?.onSubtreeModified.call(node, owner, options); } catch (e) { - console.error('error when excute experimental.callbacks.onNodeAdd', e); + console.error('error when excute experimental.callbacks.onSubtreeModified', e); } } diff --git a/packages/designer/src/document/node/node.ts b/packages/designer/src/document/node/node.ts index c69f780d5..e480d6b6e 100644 --- a/packages/designer/src/document/node/node.ts +++ b/packages/designer/src/document/node/node.ts @@ -155,9 +155,12 @@ export class Node { children: isDOMText(children) || isJSExpression(children) ? children : '', }); } else { + // 这里 props 被初始化两次,一次 new,一次 import,new 的实例需要给 propsReducer 的钩子去使用, + // import 是为了使用钩子返回的值,并非完全幂等的操作,部分行为执行两次会有 bug, + // 所以在 props 里会对 new / import 做一些区别化的解析 this.props = new Props(this, props, extras); this._children = new NodeChildren(this as ParentalNode, this.initialChildren(children)); - this._children.interalInitParent(); + this._children.internalInitParent(); this.props.import(this.upgradeProps(this.initProps(props || {})), this.upgradeProps(extras || {})); this.setupAutoruns(); } @@ -258,14 +261,6 @@ export class Node { return; } - if (this._parent) { - if (this.isSlot()) { - this._parent.removeSlot(this, false); - } else { - this._parent.children.delete(this, false, useMutator); - } - } - this._parent = parent; if (parent) { this.document.removeWillPurge(this); @@ -298,12 +293,12 @@ export class Node { /** * 移除当前节点 */ - remove(useMutator = true) { + remove(useMutator = true, purge = true) { if (this.parent) { if (this.isSlot()) { - this.parent.removeSlot(this, true); + this.parent.removeSlot(this, purge); } else { - this.parent.children.delete(this, true, useMutator); + this.parent.children.delete(this, purge, useMutator); } } } @@ -653,12 +648,14 @@ export class Node { if (i < 0) { return false; } - const deleted = this._slots.splice(i, 1)[0]; if (purge) { // should set parent null - deleted.internalSetParent(null); - deleted.purge(); + slotNode.internalSetParent(null, false); + slotNode.purge(); } + this.document.unlinkNode(slotNode); + this.document.selection.remove(slotNode.id); + this._slots.splice(i, 1); return false; } @@ -699,20 +696,10 @@ export class Node { if (this.purged) { return; } - // if (this._parent) { - // // should remove thisNode before purge - // this.remove(useMutator); - // return; - // } this.purged = true; - if (this.isParental()) { - this.children.purge(useMutator); - } this.autoruns?.forEach((dispose) => dispose()); this.props.purge(); - this.document.internalRemoveAndPurgeNode(this); this.document.destroyNode(this); - this.remove(useMutator); } /** diff --git a/packages/designer/src/document/node/props/prop.ts b/packages/designer/src/document/node/props/prop.ts index b27b6e60b..5acfcc757 100644 --- a/packages/designer/src/document/node/props/prop.ts +++ b/packages/designer/src/document/node/props/prop.ts @@ -22,6 +22,37 @@ export class Prop implements IPropParent { readonly isProp = true; readonly owner: Node; + private stash: PropStash | undefined; + + /** + * 键值 + */ + @obx key: string | number | undefined; + /** + * 扩展值 + */ + @obx spread: boolean; + + readonly props: Props; + readonly options: any; + + constructor( + public parent: IPropParent, + value: CompositeValue | UNSET = UNSET, + key?: string | number, + spread = false, + options = {}, + ) { + this.owner = parent.owner; + this.props = parent.props; + this.key = key; + this.spread = spread; + this.options = options; + if (value !== UNSET) { + this.setValue(value); + } + } + /** * @see SettingTarget */ @@ -197,7 +228,7 @@ export class Prop implements IPropParent { } else if (Array.isArray(val)) { this._type = 'list'; } else if (isPlainObject(val)) { - if (isJSSlot(val)) { + if (isJSSlot(val) && this.options.propsMode !== 'init') { this.setAsSlot(val); return; } @@ -347,34 +378,6 @@ export class Prop implements IPropParent { return this._maps; } - private stash: PropStash | undefined; - - /** - * 键值 - */ - @obx key: string | number | undefined; - /** - * 扩展值 - */ - @obx spread: boolean; - - readonly props: Props; - - constructor( - public parent: IPropParent, - value: CompositeValue | UNSET = UNSET, - key?: string | number, - spread = false, - ) { - this.owner = parent.owner; - this.props = parent.props; - if (value !== UNSET) { - this.setValue(value); - } - this.key = key; - this.spread = spread; - } - /** * 获取某个属性 * @param stash 如果不存在,临时获取一个待写入 diff --git a/packages/designer/src/document/node/props/props.ts b/packages/designer/src/document/node/props/props.ts index 02852816f..e9c73ccd3 100644 --- a/packages/designer/src/document/node/props/props.ts +++ b/packages/designer/src/document/node/props/props.ts @@ -57,9 +57,9 @@ export class Props implements IPropParent { constructor(readonly owner: Node, value?: PropsMap | PropsList | null, extras?: object) { if (Array.isArray(value)) { this.type = 'list'; - this.items = value.map(item => new Prop(this, item.value, item.name, item.spread)); + this.items = value.map(item => new Prop(this, item.value, item.name, item.spread, { propsMode: 'init' })); } else if (value != null) { - this.items = Object.keys(value).map(key => new Prop(this, value[key], key)); + this.items = Object.keys(value).map(key => new Prop(this, value[key], key, false, { propsMode: 'init' })); } if (extras) { Object.keys(extras).forEach(key => { diff --git a/packages/editor-preset-vision/src/editor.ts b/packages/editor-preset-vision/src/editor.ts index d9e8b767f..86188d288 100644 --- a/packages/editor-preset-vision/src/editor.ts +++ b/packages/editor-preset-vision/src/editor.ts @@ -26,21 +26,10 @@ export const designer = new Designer({ editor: editor }); editor.set(Designer, designer); editor.set('designer', designer); -let nodeCache: any = {}; designer.project.onCurrentDocumentChange((doc) => { - nodeCache = {}; - doc.nodesMap.forEach((node) => { - nodeCache[node.id] = node; - }); doc.onRendererReady(() => { bus.emit(VE_EVENTS.VE_PAGE_PAGE_READY); }); - doc.onNodeCreate((node) => { - nodeCache[node.id] = node; - }); - doc.onNodeDestroy((node) => { - delete nodeCache[node.id]; - }); }); interface Variable { @@ -89,6 +78,18 @@ function upgradePropsReducer(props: any) { // 升级 Props designer.addPropsReducer(upgradePropsReducer, TransformStage.Upgrade); +function getCurrentFieldIds() { + const fieldIds: any = []; + const nodesMap = designer?.currentDocument?.nodesMap || new Map(); + nodesMap.forEach((curNode: any) => { + const fieldId = nodesMap?.get(curNode.id)?.getPropValue('fieldId'); + if (fieldId) { + fieldIds.push(fieldId); + } + }); + return fieldIds; +} + // 节点 props 初始化 designer.addPropsReducer((props, node) => { // run initials @@ -96,18 +97,10 @@ designer.addPropsReducer((props, node) => { ...props, }; if (newProps.fieldId) { - const fieldIds: any = []; - Object.keys(nodeCache).forEach(nodeId => { - if (nodeId === node.id) { - return; - } - const fieldId = nodeCache[nodeId].getPropValue('fieldId'); - if (fieldId) { - fieldIds.push(fieldId); - } - }); + const fieldIds = getCurrentFieldIds(); + // 全局的关闭 uniqueIdChecker 信号,在 ve-utils 中实现 - if (fieldIds.indexOf(props.fieldId) >= 0 && !window.__disable_unique_id_checker__) { + if (fieldIds.indexOf(props.fieldId) >= 0 && !(window as any).__disable_unique_id_checker__) { newProps.fieldId = undefined; } }