From 356874599a8be56289e614c47d836d6465a5deb1 Mon Sep 17 00:00:00 2001 From: * <8> Date: Tue, 25 Jan 2022 09:33:01 +0800 Subject: [PATCH] Match-id-b3144e462876f69f20c7c56f50a88fa9cd532298 --- libs/horizon/src/dom/DOMInternalKeys.ts | 2 +- .../src/renderer/diff/nodeDiffComparator.ts | 10 +++- .../src/renderer/submit/LifeCycleHandler.ts | 53 ++++++++++++++++++- libs/horizon/src/renderer/submit/Submit.ts | 7 ++- libs/horizon/src/renderer/vnode/VNode.ts | 3 +- libs/horizon/src/renderer/vnode/VNodeFlags.ts | 7 ++- 6 files changed, 74 insertions(+), 8 deletions(-) diff --git a/libs/horizon/src/dom/DOMInternalKeys.ts b/libs/horizon/src/dom/DOMInternalKeys.ts index dec6fed1..724ae509 100644 --- a/libs/horizon/src/dom/DOMInternalKeys.ts +++ b/libs/horizon/src/dom/DOMInternalKeys.ts @@ -16,7 +16,7 @@ import { const prefix = '_horizon'; -const internalKeys = { +export const internalKeys = { VNode: `${prefix}VNode`, props: `${prefix}Props`, events: `${prefix}Events`, diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index cf2a7993..b805f71b 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -1,7 +1,7 @@ import type { VNode } from '../Types'; import { FlagUtils } from '../vnode/VNodeFlags'; import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType'; -import { DomText, DomPortal, Fragment } from '../vnode/VNodeTags'; +import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags'; import {updateVNode, createVNode, createVNodeFromElement, updateVNodePath} from '../vnode/VNodeCreator'; import { isSameType, @@ -320,7 +320,13 @@ function diffArrayNodes( // 3. 新节点已经处理完成 if (leftIdx === rightIdx) { if (isComparing) { - deleteVNodes(parentNode, oldNode, rightEndOldNode); + if (firstChild && parentNode.tag === DomComponent && newChildren.length === 0) { + // if (false) { + FlagUtils.markClear(parentNode); + parentNode.ClearChild = firstChild; + } else { + deleteVNodes(parentNode, oldNode, rightEndOldNode); + } } if (rightNewNode) { diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 78a308d4..190763cf 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -17,7 +17,7 @@ import { SuspenseComponent, MemoComponent, } from '../vnode/VNodeTags'; -import { FlagUtils, ResetText } from '../vnode/VNodeFlags'; +import { FlagUtils, ResetText, Clear } from '../vnode/VNodeFlags'; import { mergeDefaultProps } from '../render/LazyComponent'; import { submitDomUpdate, @@ -43,6 +43,7 @@ import { findDomParent, getSiblingDom, } from '../vnode/VNodeUtils'; import { shouldAutoFocus } from '../../dom/utils/Common'; +import { internalKeys } from '../../dom/DOMInternalKeys'; function callComponentWillUnmount(vNode: VNode, instance: any) { try { @@ -307,6 +308,55 @@ function unmountDomComponents(vNode: VNode): void { }); } +function submitClear(vNode: VNode): void { + const realNode = vNode.realNode; + const cloneDom = realNode.cloneNode(false); // 复制节点后horizon的两个属性消失 + cloneDom[internalKeys.VNode] = realNode[internalKeys.VNode]; + cloneDom[internalKeys.props] = realNode[internalKeys.props]; + // 删除节点 + let currentParentIsValid = false; + + // 这两个变量要一起更新 + let currentParent; + + travelVNodeTree(vNode, (node) => { + if (!currentParentIsValid) { + const parentObj = findDomParent(node); + currentParent = parentObj.parentDom; + currentParentIsValid = true; + } + const tag = node.tag; + if (tag === DomComponent || tag === DomText) { + // 卸载子vNode,递归遍历子vNode + unmountNestedVNodes(node.ClearChild); // node.child 为空,需要添加原有的child + + // 在所有子项都卸载后,删除dom树中的节点 + removeChildDom(currentParent, node.realNode); + console.log(currentParent); + currentParent.append(cloneDom); + vNode.realNode = cloneDom; + FlagUtils.removeFlag(vNode, Clear); + vNode.ClearChild = null; + } else if (tag === DomPortal) { + console.log(DomPortal); + if (node.child !== null) { + currentParent = node.outerDom; + } + } else { + unmountVNode(node); + } + }, (node) => { + // 如果是dom不用再遍历child + const tag = node.tag; + return tag === DomComponent || tag === DomText; + }, null, (node) => { + if (node.tag === DomPortal) { + // 当离开portal,需要重新设置parent + currentParentIsValid = false; + } + }); +} + function submitDeletion(vNode: VNode): void { // 遍历所有子节点:删除dom节点,detach ref 和 调用componentWillUnmount() unmountDomComponents(vNode); @@ -353,6 +403,7 @@ export { submitResetTextContent, submitAddition, submitDeletion, + submitClear, submitUpdate, callAfterSubmitLifeCycles, attachRef, diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index e76f0b97..446569bb 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -9,7 +9,7 @@ import { attachRef, callAfterSubmitLifeCycles, callBeforeSubmitLifeCycles, submitDeletion, submitAddition, - submitResetTextContent, submitUpdate, detachRef, + submitResetTextContent, submitUpdate, detachRef, submitClear, } from './LifeCycleHandler'; import {tryRenderRoot, setProcessing} from '../TreeBuilder'; import { @@ -121,7 +121,7 @@ function submit(dirtyNodes: Array) { } } - const {Addition, Update, Deletion} = node.flags; + const {Addition, Update, Deletion, Clear} = node.flags; if (Addition && Update) { // Addition submitAddition(node); @@ -138,6 +138,9 @@ function submit(dirtyNodes: Array) { } else if (Deletion) { submitDeletion(node); } + if (Clear) { + submitClear(node); + } } } catch (error) { throwIfTrue(node === null, 'Should be working on an effect.'); diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 71c0856e..9cac9cc2 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -60,8 +60,9 @@ export class VNode { Interrupted?: boolean; ShouldCapture?: boolean; ForceUpdate?: boolean; + Clear?: boolean; } = {}; - + ClearChild: VNode|null = null; // one tree相关属性 isCreated: boolean = true; oldHooks: Array> = []; // 保存上一次执行的hook diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts index 62e02be1..449d6baa 100644 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts @@ -18,9 +18,10 @@ export const Interrupted = 'Interrupted'; export const ShouldCapture = 'ShouldCapture'; // For suspense export const ForceUpdate = 'ForceUpdate'; +export const Clear = 'Clear'; const FlagArr = [Addition, Update, Deletion, ResetText, Callback, - DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate]; + DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate, Clear]; const LifecycleEffectArr = [Update, Callback, Ref, Snapshot]; @@ -90,5 +91,9 @@ export class FlagUtils { static markForceUpdate(node: VNode) { node.flags.ForceUpdate = true; } + + static markClear(node: VNode) { + node.flags.Clear = true; + } }