Match-id-a1095c6e547ae06557735fa486ddd1994eed8c20
This commit is contained in:
parent
d217302bf1
commit
c766853a89
|
@ -1,8 +0,0 @@
|
||||||
import type {VNode} from '../Types';
|
|
||||||
|
|
||||||
// 当前所有者是应拥有当前正在构建的任何组件的组件。
|
|
||||||
const ProcessingVNode: { val: VNode | null } = {
|
|
||||||
val: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProcessingVNode;
|
|
|
@ -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<VNode> | 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<any, any>> = []; // 保存hook
|
|
||||||
suspenseChildStatus: string = ''; // Suspense的Children是否显示
|
|
||||||
depContexts: Array<ContextType<any>> = []; // FunctionComponent和ClassComponent对context的依赖列表
|
|
||||||
isDepContextChange: boolean = false; // context是否变更
|
|
||||||
dirtyNodes: Array<VNode> = []; // 需要改动的节点数组
|
|
||||||
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<any, any>> = []; // 保存上一次执行的hook
|
|
||||||
oldState: any = null;
|
|
||||||
oldRef: RefType | ((handle: any) => void) | null = null;
|
|
||||||
suspenseChildThrow = false;
|
|
||||||
oldSuspenseChildStatus: string = ''; // 上一次Suspense的Children是否显示
|
|
||||||
oldChildren: Array<VNode> | null = null;
|
|
||||||
suspenseDidCapture: boolean = false; // suspense是否捕获了异常
|
|
||||||
promiseResolve: boolean = false; // suspense的promise是否resolve
|
|
||||||
|
|
||||||
path: Array<number> = []; // 保存从根到本节点的路径
|
|
||||||
toUpdateNodes: Set<VNode> | 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<VNode>();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setContext(contextName, value) {
|
|
||||||
this.contexts[contextName] = value;
|
|
||||||
}
|
|
||||||
getContext(contextName) {
|
|
||||||
return this.contexts[contextName];
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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<VNode> | 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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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';
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue