From c766853a8941ceaa4cc5e60581bf655b3c4f65d0 Mon Sep 17 00:00:00 2001 From: * <8> Date: Sat, 25 Dec 2021 15:09:41 +0800 Subject: [PATCH] Match-id-a1095c6e547ae06557735fa486ddd1994eed8c20 --- .../src/renderer/vnode/ProcessingVNode.ts | 8 - libs/horizon/src/renderer/vnode/VNode.ts | 98 ------ .../src/renderer/vnode/VNodeCreator.ts | 191 ------------ libs/horizon/src/renderer/vnode/VNodeFlags.ts | 92 ------ .../src/renderer/vnode/VNodeShouldUpdate.ts | 66 ----- libs/horizon/src/renderer/vnode/VNodeTags.ts | 21 -- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 278 ------------------ 7 files changed, 754 deletions(-) delete mode 100644 libs/horizon/src/renderer/vnode/ProcessingVNode.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNode.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNodeCreator.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNodeFlags.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNodeShouldUpdate.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNodeTags.ts delete mode 100644 libs/horizon/src/renderer/vnode/VNodeUtils.ts diff --git a/libs/horizon/src/renderer/vnode/ProcessingVNode.ts b/libs/horizon/src/renderer/vnode/ProcessingVNode.ts deleted file mode 100644 index 1110242c..00000000 --- a/libs/horizon/src/renderer/vnode/ProcessingVNode.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type {VNode} from '../Types'; - -// 当前所有者是应拥有当前正在构建的任何组件的组件。 -const ProcessingVNode: { val: VNode | null } = { - val: null, -}; - -export default ProcessingVNode; diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts deleted file mode 100644 index f726c4a4..00000000 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ /dev/null @@ -1,98 +0,0 @@ -/** - * 虚拟DOM结构体 - */ -import {TreeRoot} from './VNodeTags'; -import type {VNodeTag} from './VNodeTags'; -import type {RefType, ContextType} from '../Types'; -import type {Hook} from '../hooks/HookType'; - -export class VNode { - tag: VNodeTag; - key: string | null; // 唯一标识符 - type: any = null; - realNode: any = null; // 如果是类,则存放实例;如果是div这种,则存放真实DOM; - - // 关系结构 - parent: VNode | null = null; // 父节点 - children: Array | null = null; // 子节点 - cIndex: number = 0; // 节点在children数组中的位置 - eIndex: number = 0; // HorizonElement在jsx中的位置,例如:jsx中的null不会生成vNode,所以eIndex和cIndex不一致 - - ref: RefType | ((handle: any) => void) | null = null; // 包裹一个函数,submit阶段使用,比如将外部useRef生成的对象赋值到ref上 - props: any; // 传给组件的props的值,类组件包含defaultProps,Lazy组件不包含 - oldProps: any = null; - - suspensePromises: any = null; // suspense组件的promise列表 - changeList: any = null; // DOM的变更列表 - effectList: any[] = []; // useEffect 的更新数组 - updates: any[] = null; // TreeRoot和ClassComponent使用的更新数组 - stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 - isForceUpdate: boolean = false; // 是否使用强制更新 - - state: any = null; // ClassComponent和TreeRoot的状态 - hooks: Array> = []; // 保存hook - suspenseChildStatus: string = ''; // Suspense的Children是否显示 - depContexts: Array> = []; // FunctionComponent和ClassComponent对context的依赖列表 - isDepContextChange: boolean = false; // context是否变更 - dirtyNodes: Array = []; // 需要改动的节点数组 - shouldUpdate: boolean = false; - childShouldUpdate: boolean = false; - outerDom: any; - task: any; - - // 使用这个变量来记录修改前的值,用于恢复。 - contexts = {}; - // 因为LazyComponent会修改tag和type属性,为了能识别,增加一个属性 - isLazyComponent: boolean = false; - - // 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType - lazyType: any = null; - flags: { - Addition?: boolean, - Update?: boolean, - Deletion?: boolean, - ResetText?: boolean, - Callback?: boolean, - DidCapture?: boolean, - Ref?: boolean, - Snapshot?: boolean, - Interrupted?: boolean, - ShouldCapture?: boolean, - ForceUpdate?: boolean, - } = {}; - - // one tree相关属性 - isCreated: boolean = true; - oldHooks: Array> = []; // 保存上一次执行的hook - oldState: any = null; - oldRef: RefType | ((handle: any) => void) | null = null; - suspenseChildThrow = false; - oldSuspenseChildStatus: string = ''; // 上一次Suspense的Children是否显示 - oldChildren: Array | null = null; - suspenseDidCapture: boolean = false; // suspense是否捕获了异常 - promiseResolve: boolean = false; // suspense的promise是否resolve - - path: Array = []; // 保存从根到本节点的路径 - toUpdateNodes: Set | null = null; // 保存要更新的节点 - - constructor(tag: VNodeTag, props: any, key: null | string, outerDom) { - this.tag = tag; // 对应组件的类型,比如ClassComponent等 - this.key = key; - - this.props = props; - - // 根节点 - if (tag === TreeRoot) { - this.outerDom = outerDom; - this.task = null; - this.toUpdateNodes = new Set(); - } - } - - setContext(contextName, value) { - this.contexts[contextName] = value; - } - getContext(contextName) { - return this.contexts[contextName]; - } -} diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts deleted file mode 100644 index e648e3b1..00000000 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ /dev/null @@ -1,191 +0,0 @@ -import type { VNodeTag } from './VNodeTags'; -import { FlagUtils } from './VNodeFlags'; -import { - ClassComponent, - ContextConsumer, - ContextProvider, - ForwardRef, - Fragment, - FunctionComponent, - DomComponent, - DomPortal, - TreeRoot, - DomText, - ClsOrFunComponent, - LazyComponent, - MemoComponent, - SuspenseComponent, -} from './VNodeTags'; -import { createUpdateArray } from '../UpdateHandler'; -import { - TYPE_CONTEXT, - TYPE_FORWARD_REF, TYPE_FRAGMENT, - TYPE_LAZY, - TYPE_MEMO, TYPE_PROFILER, - TYPE_PROVIDER, TYPE_STRICT_MODE, - TYPE_SUSPENSE, -} from '../utils/elementType'; -import { VNode } from './VNode'; -import {HorizonElement} from '../Types'; - -const typeLazyMap = { - [TYPE_FORWARD_REF]: ForwardRef, - [TYPE_MEMO]: MemoComponent, -}; -const typeMap = { - ...typeLazyMap, - [TYPE_PROVIDER]: ContextProvider, - [TYPE_CONTEXT]: ContextConsumer, - [TYPE_LAZY]: LazyComponent, -}; - -const newVirtualNode = function(tag: VNodeTag, key?: null | string, vNodeProps?: any, outerDom?: any): VNode { - return new VNode(tag, vNodeProps, key, outerDom); -}; - -function isClassComponent(comp: Function) { - // 如果使用 getPrototypeOf 方法获取构造函数,不能兼容业务组组件继承组件的使用方式,会误认为是函数组件 - // 如果使用静态属性,部分函数高阶组件会将类组件的静态属性复制到自身,导致误判为类组件 - // 既然已经兼容使用了该标识符,那么继续使用 - return comp.prototype?.isReactComponent === true; -} - -// 解析懒组件的tag -export function getLazyVNodeTag(lazyComp: any): string { - let vNodeTag = ClsOrFunComponent; - if (typeof lazyComp === 'function') { - vNodeTag = isClassComponent(lazyComp) ? ClassComponent : FunctionComponent; - } else if (lazyComp !== undefined && lazyComp !== null && typeLazyMap[lazyComp.vtype]) { - vNodeTag = typeLazyMap[lazyComp.vtype]; - } - return vNodeTag; -} - -// 创建processing -export function updateVNode(vNode: VNode, vNodeProps?: any): VNode { - if (vNode.tag === ClassComponent) { - vNode.oldState = vNode.state; - } - - if (vNode.tag === SuspenseComponent) { - vNode.oldSuspenseChildStatus = vNode.suspenseChildStatus; - vNode.oldChildren = vNode.children; - } - - vNode.oldProps = vNode.props; - vNode.props = vNodeProps; - - vNode.oldRef = vNode.ref; - - FlagUtils.setNoFlags(vNode); - vNode.dirtyNodes = []; - vNode.isCreated = false; - - return vNode; -} - -function getVNodeTag(type: any) { - let vNodeTag = ClsOrFunComponent; - let isLazy = false; - - if (typeof type === 'function') { - if (isClassComponent(type)) { - vNodeTag = ClassComponent; - } - } else if (typeof type === 'string') { - vNodeTag = DomComponent; - } else if (type === TYPE_SUSPENSE) { - vNodeTag = SuspenseComponent; - } else if (typeof type === 'object' && type !== null && typeMap[type.vtype]) { - vNodeTag = typeMap[type.vtype]; - isLazy = type.vtype === TYPE_LAZY; - } else { - throw Error(`Component type is invalid, got: ${type == null ? type : typeof type}`); - } - return { vNodeTag, isLazy }; -} - -export function createVNode(tag: VNodeTag | string, ...secondArg) { - let vNode = null; - switch (tag) { - case Fragment: - const [fragmentKey, fragmentProps] = secondArg; - vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps); - vNode.shouldUpdate = true; - break; - case DomText: - const content = secondArg[0]; - vNode = newVirtualNode(DomText, null, content); - vNode.shouldUpdate = true; - break; - case DomPortal: - const portal = secondArg[0]; - const children = portal.children ?? []; - vNode = newVirtualNode(DomPortal, portal.key, children); - vNode.shouldUpdate = true; - vNode.outerDom = portal.outerDom; - break; - case 'props': - const [type, key, props] = secondArg; - - const { vNodeTag, isLazy } = getVNodeTag(type); - - vNode = newVirtualNode(vNodeTag, key, props); - vNode.type = type; - vNode.shouldUpdate = true; - - // lazy类型的特殊处理 - vNode.isLazyComponent = isLazy; - if (isLazy) { - vNode.lazyType = type; - } - break; - case TreeRoot: - // 创建treeRoot - vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]); - vNode.path.push(0); - - createUpdateArray(vNode); - break; - } - - return vNode; -} - -export function updateVNodePath(vNode: VNode) { - vNode.path = [...vNode.parent.path, vNode.cIndex]; -} - -export function createVNodeFromElement(element: HorizonElement): VNode { - const type = element.type; - const key = element.key; - const props = element.props; - - if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { - return createVNode(Fragment, key, props.children); - } else { - return createVNode('props', type, key, props); - } -} - -// 直接更新子节点属性即可,不需要diff -export function onlyUpdateChildVNodes(processing: VNode): Array | null { - // 检查子树是否需要更新 - if (processing.childShouldUpdate) { - // 此vNode无需更新,但是子树需要 - if (!processing.isCreated && processing.children && processing.children.length) { - // 更新子节点 - processing.children.forEach(child => { - updateVNode(child, child.props); - updateVNodePath(child); - }); - } - - // 返回子节点,继续遍历 - return processing.children; - } - - // 子树无需工作 - return null; -} - diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts deleted file mode 100644 index 7259beb7..00000000 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ /dev/null @@ -1,92 +0,0 @@ -/** - * vNode结构的变化标志 - */ - -import type { VNode } from '../Types'; - -// vNode节点的flags -export const Addition = 'Addition'; -export const Update = 'Update'; -export const Deletion = 'Deletion'; -export const ResetText = 'ResetText'; -export const Callback = 'Callback'; -export const DidCapture = 'DidCapture'; -export const Ref = 'Ref'; -export const Snapshot = 'Snapshot'; -// 被中断了,抛出错误的vNode以及它的父vNode -export const Interrupted = 'Interrupted'; -export const ShouldCapture = 'ShouldCapture'; -// For suspense -export const ForceUpdate = 'ForceUpdate'; - -const flagArr = [Addition, Update, Deletion, ResetText, Callback, DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate]; - -const LifecycleEffectArr = [Update, Callback, Ref, Snapshot]; - -function resetFlag(node) { - node.flags = {}; -} - -export class FlagUtils { - static removeFlag(node: VNode, flag: string) { - node.flags[flag] = false; - } - static removeLifecycleEffectFlags(node) { - LifecycleEffectArr.forEach(key => { - node.flags[key] = false; - }); - } - static hasAnyFlag(node: VNode) { // 有标志位 - let keyFlag = false; - flagArr.forEach(key => { - if (node.flags[key]) { - keyFlag = true; - } - }); - return keyFlag; - } - - static setNoFlags(node: VNode) { - resetFlag(node); - } - - static markAddition(node: VNode) { - node.flags.Addition = true; - } - static setAddition(node: VNode) { - resetFlag(node); - node.flags.Addition = true; - } - static markUpdate(node: VNode) { - node.flags.Update = true; - } - static setDeletion(node: VNode) { - resetFlag(node); - node.flags.Deletion = true; - } - static markContentReset(node: VNode) { - node.flags.ResetText = true; - } - static markCallback(node: VNode) { - node.flags.Callback = true; - } - static markDidCapture(node: VNode) { - node.flags.DidCapture = true; - } - static markShouldCapture(node: VNode) { - node.flags.ShouldCapture = true; - } - static markRef(node: VNode) { - node.flags.Ref = true; - } - static markSnapshot(node: VNode) { - node.flags.Snapshot = true; - } - static markInterrupted(node: VNode) { - node.flags.Interrupted = true; - } - static markForceUpdate(node: VNode) { - node.flags.ForceUpdate = true; - } -} - diff --git a/libs/horizon/src/renderer/vnode/VNodeShouldUpdate.ts b/libs/horizon/src/renderer/vnode/VNodeShouldUpdate.ts deleted file mode 100644 index 00ebe158..00000000 --- a/libs/horizon/src/renderer/vnode/VNodeShouldUpdate.ts +++ /dev/null @@ -1,66 +0,0 @@ -// 从当前节点向上遍历,更新shouldUpdate和childShouldUpdate -import {VNode} from './VNode'; -import {TreeRoot} from './VNodeTags'; - -export function updateShouldUpdateOfTree(vNode: VNode): VNode | null { - vNode.shouldUpdate = true; - - // 一直向上遍历,修改childShouldUpdate - let node = vNode; - let parent = vNode.parent; - while (parent !== null) { - parent.childShouldUpdate = true; - node = parent; - parent = parent.parent; - } - - if (node.tag === TreeRoot) { - node.shouldUpdate = true; - // 返回根节点 - return node; - } - - return null; -} - -// 设置节点的childShouldUpdate -export function updateChildShouldUpdate(vNode: VNode) { - const children = vNode.children || []; - - for (let i = 0; i < children.length; i++) { - const child = children[i]; - if (child && (child.shouldUpdate || child.childShouldUpdate)) { - vNode.childShouldUpdate = true; - return; - } - } - vNode.childShouldUpdate = false; -} - -// 设置节点的所有父节点的childShouldUpdate -export function updateParentsChildShouldUpdate(vNode: VNode) { - let node = vNode.parent; - let isShouldUpdate = vNode.shouldUpdate || vNode.childShouldUpdate; - - if (isShouldUpdate) { // 开始节点是shouldUpdate或childShouldUpdate - setParentsChildShouldUpdate(node); - } else { - while (node !== null) { - updateChildShouldUpdate(node); - node = node.parent; - } - } -} - -// 更新从当前节点到根节点的childShouldUpdate为true -export function setParentsChildShouldUpdate(parent: VNode | null) { - let node = parent; - while (node !== null) { - if (node.childShouldUpdate) { - break; - } - node.childShouldUpdate = true; - - node = node.parent; - } -} diff --git a/libs/horizon/src/renderer/vnode/VNodeTags.ts b/libs/horizon/src/renderer/vnode/VNodeTags.ts deleted file mode 100644 index 2ec1db13..00000000 --- a/libs/horizon/src/renderer/vnode/VNodeTags.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * 定义vNode的类型 - */ -export type VNodeTag = string; - -export const TreeRoot = 'TreeRoot'; // tree的根节点,用于存放一些tree级的变量 -export const FunctionComponent = 'FunctionComponent'; -export const ClassComponent = 'ClassComponent'; -export const ClsOrFunComponent = 'ClsOrFunComponent'; -export const DomPortal = 'DomPortal'; -export const DomComponent = 'DomComponent'; -export const DomText = 'DomText'; -export const Fragment = 'Fragment'; -export const ContextConsumer = 'ContextConsumer'; -export const ContextProvider = 'ContextProvider'; -export const ForwardRef = 'ForwardRef'; -export const Profiler = 'Profiler'; -export const SuspenseComponent = 'SuspenseComponent'; -export const MemoComponent = 'MemoComponent'; -export const LazyComponent = 'LazyComponent'; -export const IncompleteClassComponent = 'IncompleteClassComponent'; diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts deleted file mode 100644 index 3b921738..00000000 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ /dev/null @@ -1,278 +0,0 @@ -/** - * 提供:vNode的“遍历”,“查找”,“判断”的相关工具方法 - */ - -import type {VNode} from '../Types'; - -import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags'; -import {isComment} from '../../dom/utils/Common'; -import {getNearestVNode} from '../../dom/DOMInternalKeys'; - -export function getSiblingVNode(node) { - let siblingVNode = null; - const index = node.cIndex; - if (node && node.parent && node.parent.children && node.parent.children.length > index + 1) { - siblingVNode = node.parent.children[index + 1]; - } - return siblingVNode; -} - -export function getFirstChild(vNode: VNode) { - return (vNode.children && vNode.children.length) ? vNode.children[0] : null; -} - -// 从beginVNode开始深度遍历vNode树,对每个vNode调用handleVNode方法 -export function travelVNodeTree( - beginVNode: VNode, - handleVNode: Function, - childFilter: Function = () => false, // 返回true不处理child - finishVNode?: VNode, // 结束遍历节点,有时候和beginVNode不相同 - handleWhenToParent?: Function -): VNode | null { - const overVNode = finishVNode || beginVNode; - let node = beginVNode; - - while (true) { - const ret = handleVNode(node); - // 如果处理一个vNode时有返回值,则中断遍历 - if (ret) { - return ret; - } - - // 找子节点 - const childVNode = getFirstChild(node); - if (childVNode !== null && !childFilter(node)) { - childVNode.parent = node; - node = childVNode; - continue; - } - - // 回到开始节点 - if (node === overVNode) { - return null; - } - - // 找兄弟,没有就往上再找兄弟 - while (getSiblingVNode(node) === null) { - if (node.parent === null || node.parent === overVNode) { - return null; - } - node = node.parent; - - if (typeof handleWhenToParent === 'function') { - handleWhenToParent(node); - } - } - // 找到兄弟 - const siblingVNode = getSiblingVNode(node); - siblingVNode.parent = node.parent; - node = siblingVNode; - } -} - -// 置空vNode -export function clearVNode(vNode: VNode) { - clearOneVNode(vNode); -} - -function clearOneVNode(vNode: VNode) { - vNode.children = []; - vNode.depContexts = []; - vNode.dirtyNodes = []; - vNode.oldProps = null; - vNode.state = null; - vNode.hooks = []; - vNode.suspenseChildStatus = ''; - vNode.props = null; - vNode.parent = null; - vNode.suspensePromises = null; - vNode.changeList = null; - vNode.effectList = []; - vNode.updates = null; - - vNode.oldHooks = []; - vNode.oldState = null; - vNode.oldRef = null; - vNode.suspenseChildThrow = false; - vNode.oldSuspenseChildStatus = ''; - vNode.oldChildren = null; - - vNode.path = []; - vNode.toUpdateNodes = null; -} - -// 是dom类型的vNode -export function isDomVNode(node: VNode) { - return node.tag === DomComponent || node.tag === DomText; -} - -// 是容器类型的vNode -function isDomContainer(vNode: VNode): boolean { - return ( - vNode.tag === DomComponent || - vNode.tag === TreeRoot || - vNode.tag === DomPortal - ); -} - -// 找到DOM类型的父 -export function findDomParent(vNode: VNode) { - let parent = vNode.parent; - - while (parent !== null) { - switch (parent.tag) { - case DomComponent: - return {parent, parentDom: parent.realNode}; - case TreeRoot: - case DomPortal: - return {parent, parentDom: parent.outerDom}; - } - parent = parent.parent; - } - - return null; -} - -export function findDomVNode(vNode: VNode): VNode | null { - return travelVNodeTree(vNode, (node) => { - if (node.tag === DomComponent || node.tag === DomText) { - return node; - } - }); -} - -export function findDOMByClassInst(inst) { - const vNode = inst._vNode; - if (vNode === undefined) { - throw new Error('Unable to find the vNode by class instance.'); - } - - const domVNode = findDomVNode(vNode); - - return domVNode !== null ? domVNode.realNode : null; -} - -// 判断dom树是否已经挂载 -export function isMounted(vNode: VNode) { - const rootNode = getTreeRootVNode(vNode); - // 如果根节点是 Dom 类型节点,表示已经挂载 - return rootNode.tag === TreeRoot; -} - -function getTreeRootVNode(vNode) { - let node = vNode; - while (node.parent) { - node = node.parent; - } - return node; -} - -// 找到相邻的DOM -export function getSiblingDom(vNode: VNode): Element | null { - let node: VNode = vNode; - - findSibling: while (true) { - // 没有兄弟节点,找父节点 - while (getSiblingVNode(node) === null) { - // 没父节点,或父节点已经是根节点,则返回 - if (node.parent === null || isDomContainer(node.parent)) { - return null; - } - node = node.parent; - } - - const siblingVNode = getSiblingVNode(node); - siblingVNode.parent = node.parent; - node = siblingVNode; - - // 如果不是dom节点,往下找 - while (!isDomVNode(node)) { - // 如果节点也是Addition - if (node.flags.Addition) { - continue findSibling; - } - - // 没有子节点,或是DomPortal - if (!node.children || !node.children.length || node.tag === DomPortal) { - continue findSibling; - } else { - const childVNode = getFirstChild(node); - childVNode.parent = node; - node = childVNode; - } - } - - if (!node.flags.Addition) { - // 找到 - return node.realNode; - } - } -} - -function isSameContainer( - container: Element, - targetContainer: EventTarget, -): boolean { - if (container === targetContainer) { - return true; - } - // 注释类型的节点 - if (isComment(container) && container.parentNode === targetContainer) { - return true - } - return false; -} - -function isPortalRoot(vNode, targetContainer) { - if (vNode.tag === DomPortal) { - let topVNode = vNode.parent; - while (topVNode !== null) { - const grandTag = topVNode.tag; - if (grandTag === TreeRoot || grandTag === DomPortal) { - const topContainer = topVNode.outerDom; - // 如果topContainer是targetContainer,不需要在这里处理 - if (isSameContainer(topContainer, targetContainer)) { - return true; - } - } - topVNode = topVNode.parent; - } - return false; - } - return false; -} - -// 获取根vNode节点 -export function getExactNode(targetVNode, targetContainer) { - // 确认vNode节点是否准确,portal场景下可能祖先节点不准确 - let vNode = targetVNode; - while (vNode !== null) { - if (vNode.tag === TreeRoot || vNode.tag === DomPortal) { - let container = vNode.outerDom; - if (isSameContainer(container, targetContainer)) { - break; - } - if (isPortalRoot(vNode, targetContainer)) { - return null; - } - while (container !== null) { - const parentNode = getNearestVNode(container); - if (parentNode === null) { - return null; - } - if (parentNode.tag === DomComponent || parentNode.tag === DomText) { - vNode = parentNode; - return getExactNode(vNode, targetContainer); - } - container = container.parentNode; - } - } - vNode = vNode.parent; - } - if (vNode === null) { - return null; - } - return targetVNode; -} - -