Match-id-1973f30585c9bb87995fad4913f5c677e0601e84
This commit is contained in:
commit
b1458fea04
|
@ -14,14 +14,13 @@ import {
|
||||||
TreeRoot,
|
TreeRoot,
|
||||||
} from '../renderer/vnode/VNodeTags';
|
} from '../renderer/vnode/VNodeTags';
|
||||||
|
|
||||||
const suffixKey = new Date().getTime().toString();
|
|
||||||
const prefix = '_horizon';
|
const prefix = '_horizon';
|
||||||
|
|
||||||
const internalKeys = {
|
const internalKeys = {
|
||||||
VNode: `${prefix}VNode@${suffixKey}`,
|
VNode: `${prefix}VNode`,
|
||||||
props: `${prefix}Props@${suffixKey}`,
|
props: `${prefix}Props`,
|
||||||
events: `${prefix}Events@${suffixKey}`,
|
events: `${prefix}Events`,
|
||||||
nonDelegatedEvents: `${prefix}NonDelegatedEvents@${suffixKey}`,
|
nonDelegatedEvents: `${prefix}NonDelegatedEvents`,
|
||||||
};
|
};
|
||||||
|
|
||||||
// 通过 VNode 实例获取 DOM 节点
|
// 通过 VNode 实例获取 DOM 节点
|
||||||
|
|
|
@ -73,6 +73,7 @@ function isInDocument(dom) {
|
||||||
if (dom && dom.ownerDocument) {
|
if (dom && dom.ownerDocument) {
|
||||||
return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom);
|
return isNodeContainsByTargetNode(dom.ownerDocument.documentElement, dom);
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断一个标签是否有设置选择范围的能力
|
// 判断一个标签是否有设置选择范围的能力
|
||||||
|
|
|
@ -34,12 +34,12 @@ export function watchValueChange(dom) {
|
||||||
// currentVal存储最新值,并重写value的setter、getter
|
// currentVal存储最新值,并重写value的setter、getter
|
||||||
let currentVal = String(dom[keyForValue]);
|
let currentVal = String(dom[keyForValue]);
|
||||||
|
|
||||||
const setFunc = descriptor.set;
|
const setFunc = descriptor?.set;
|
||||||
Object.defineProperty(dom, keyForValue, {
|
Object.defineProperty(dom, keyForValue, {
|
||||||
...descriptor,
|
...descriptor,
|
||||||
set: function (value) {
|
set: function(value) {
|
||||||
currentVal = String(value);
|
currentVal = String(value);
|
||||||
setFunc.apply(this, [value]);
|
setFunc?.apply(this, [value]);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import {throwIfTrue} from '../renderer/utils/throwIfTrue';
|
import {throwIfTrue} from '../renderer/utils/throwIfTrue';
|
||||||
import {TYPE_ELEMENT, TYPE_PORTAL} from '../renderer/utils/elementType';
|
import {TYPE_COMMON_ELEMENT, TYPE_PORTAL} from './JSXElementType';
|
||||||
|
|
||||||
import {isValidElement, HorizonElement} from './HorizonElement';
|
import {isValidElement, JSXElement} from './JSXElement';
|
||||||
|
|
||||||
// 生成key
|
// 生成key
|
||||||
function getItemKey(item: any, index: number): string {
|
function getItemKey(item: any, index: number): string {
|
||||||
|
@ -12,45 +12,6 @@ function getItemKey(item: any, index: number): string {
|
||||||
return '.' + index.toString(36);
|
return '.' + index.toString(36);
|
||||||
}
|
}
|
||||||
|
|
||||||
function mapChildrenToArray(
|
|
||||||
children: any,
|
|
||||||
arr: Array<any>,
|
|
||||||
prefix: string,
|
|
||||||
callback?: Function,
|
|
||||||
): number | void {
|
|
||||||
const type = typeof children;
|
|
||||||
switch (type) {
|
|
||||||
// 继承原有规格,undefined和boolean类型按照null处理
|
|
||||||
case 'undefined':
|
|
||||||
case 'boolean':
|
|
||||||
callMapFun(null, arr, prefix, callback);
|
|
||||||
return;
|
|
||||||
case 'number':
|
|
||||||
case 'string':
|
|
||||||
callMapFun(children, arr, prefix, callback);
|
|
||||||
return;
|
|
||||||
case 'object':
|
|
||||||
if (children === null) {
|
|
||||||
callMapFun(null, arr, prefix, callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const vtype = children.vtype;
|
|
||||||
if (vtype === TYPE_ELEMENT || vtype === TYPE_PORTAL) {
|
|
||||||
callMapFun(children, arr, prefix, callback) ;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (Array.isArray(children)) {
|
|
||||||
processArrayChildren(children, arr, prefix, callback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new Error(
|
|
||||||
'Object is invalid as a Horizon child. '
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function processArrayChildren(
|
function processArrayChildren(
|
||||||
children: any,
|
children: any,
|
||||||
arr: Array<any>,
|
arr: Array<any>,
|
||||||
|
@ -88,11 +49,11 @@ function callMapFun(
|
||||||
? '.$' + mappedChild.key
|
? '.$' + mappedChild.key
|
||||||
: '');
|
: '');
|
||||||
// 返回一个修改key的children
|
// 返回一个修改key的children
|
||||||
mappedChild = HorizonElement(
|
mappedChild = JSXElement(
|
||||||
mappedChild.type,
|
mappedChild.type,
|
||||||
newKey,
|
newKey,
|
||||||
mappedChild.ref,
|
mappedChild.ref,
|
||||||
mappedChild._vNode,
|
mappedChild.belongClassVNode,
|
||||||
mappedChild.props,
|
mappedChild.props,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -100,6 +61,44 @@ function callMapFun(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mapChildrenToArray(
|
||||||
|
children: any,
|
||||||
|
arr: Array<any>,
|
||||||
|
prefix: string,
|
||||||
|
callback?: Function,
|
||||||
|
): number | void {
|
||||||
|
const type = typeof children;
|
||||||
|
switch (type) {
|
||||||
|
// 继承原有规格,undefined和boolean类型按照null处理
|
||||||
|
case 'undefined':
|
||||||
|
case 'boolean':
|
||||||
|
callMapFun(null, arr, prefix, callback);
|
||||||
|
return;
|
||||||
|
case 'number':
|
||||||
|
case 'string':
|
||||||
|
callMapFun(children, arr, prefix, callback);
|
||||||
|
return;
|
||||||
|
case 'object':
|
||||||
|
if (children === null) {
|
||||||
|
callMapFun(null, arr, prefix, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const vtype = children.vtype;
|
||||||
|
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
|
||||||
|
callMapFun(children, arr, prefix, callback) ;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (Array.isArray(children)) {
|
||||||
|
processArrayChildren(children, arr, prefix, callback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new Error(
|
||||||
|
'Object is invalid as a Horizon child. '
|
||||||
|
);
|
||||||
|
// No Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
|
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
|
||||||
function mapChildren(
|
function mapChildren(
|
||||||
children: any,
|
children: any,
|
||||||
|
@ -111,9 +110,7 @@ function mapChildren(
|
||||||
}
|
}
|
||||||
let count = 0;
|
let count = 0;
|
||||||
const result = [];
|
const result = [];
|
||||||
mapChildrenToArray(children, result, '', (child) => {
|
mapChildrenToArray(children, result, '', child => func.call(context, child, count++));
|
||||||
return func.call(context, child, count++);
|
|
||||||
});
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ import {
|
||||||
TYPE_PROFILER,
|
TYPE_PROFILER,
|
||||||
TYPE_STRICT_MODE,
|
TYPE_STRICT_MODE,
|
||||||
TYPE_SUSPENSE,
|
TYPE_SUSPENSE,
|
||||||
} from '../renderer/utils/elementType';
|
} from './JSXElementType';
|
||||||
|
|
||||||
import {Component, PureComponent} from '../renderer/components/BaseClassComponent';
|
import {Component, PureComponent} from '../renderer/components/BaseClassComponent';
|
||||||
import {createRef} from '../renderer/components/CreateRef';
|
import {createRef} from '../renderer/components/CreateRef';
|
||||||
|
@ -12,7 +12,7 @@ import {
|
||||||
createElement,
|
createElement,
|
||||||
cloneElement,
|
cloneElement,
|
||||||
isValidElement,
|
isValidElement,
|
||||||
} from './HorizonElement';
|
} from './JSXElement';
|
||||||
import {createContext} from '../renderer/components/context/CreateContext';
|
import {createContext} from '../renderer/components/context/CreateContext';
|
||||||
import {lazy} from '../renderer/components/Lazy';
|
import {lazy} from '../renderer/components/Lazy';
|
||||||
import {forwardRef} from '../renderer/components/ForwardRef';
|
import {forwardRef} from '../renderer/components/ForwardRef';
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
import { TYPE_ELEMENT } from '../renderer/utils/elementType';
|
import { TYPE_COMMON_ELEMENT } from './JSXElementType';
|
||||||
import ProcessingVNode from '../renderer/vnode/ProcessingVNode';
|
import { getProcessingClassVNode } from '../renderer/GlobalVar';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* vtype, 节点的类型,这里固定是element
|
* vtype 节点的类型,这里固定是element
|
||||||
* type,保存dom节点的名称或者组件的函数地址
|
* type 保存dom节点的名称或者组件的函数地址
|
||||||
* key key属性
|
* key key属性
|
||||||
* ref ref属性
|
* ref ref属性
|
||||||
* props 其他常规属性
|
* props 其他常规属性
|
||||||
*/
|
*/
|
||||||
export function HorizonElement(type, key, ref, vNode, props) {
|
export function JSXElement(type, key, ref, vNode, props) {
|
||||||
return {
|
return {
|
||||||
// Horizon元素标识符
|
// 元素标识符
|
||||||
vtype: TYPE_ELEMENT,
|
vtype: TYPE_COMMON_ELEMENT,
|
||||||
|
|
||||||
// 属于元素的内置属性
|
// 属于元素的内置属性
|
||||||
type: type,
|
type: type,
|
||||||
|
@ -20,50 +20,15 @@ export function HorizonElement(type, key, ref, vNode, props) {
|
||||||
ref: ref,
|
ref: ref,
|
||||||
props: props,
|
props: props,
|
||||||
|
|
||||||
// 记录负责创建此元素的组件。
|
// 所属的class组件
|
||||||
_vNode: vNode,
|
belongClassVNode: vNode,
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
|
|
||||||
function isValidKey(key) {
|
function isValidKey(key) {
|
||||||
return key !== 'key' && key !== 'ref' && key !== '__source';
|
return key !== 'key' && key !== 'ref' && key !== '__source';
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildElement(isClone, type, setting, ...children) {
|
|
||||||
// setting中的值优先级最高,clone情况下从 type 中取值,创建情况下直接赋值为 null
|
|
||||||
const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null);
|
|
||||||
const ref = (setting && setting.ref !== undefined) ? setting.ref : (isClone ? type.ref : null);
|
|
||||||
const props = isClone ? {...type.props} : {};
|
|
||||||
let vNode = isClone ? type._vNode : ProcessingVNode.val;
|
|
||||||
|
|
||||||
if (setting != null) {
|
|
||||||
Object.keys(setting).forEach(k => {
|
|
||||||
if (isValidKey(k)) {
|
|
||||||
props[k] = setting[k];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (setting.ref !== undefined && isClone) {
|
|
||||||
vNode = ProcessingVNode.val;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (children.length) {
|
|
||||||
props.children = children.length === 1 ? children[0] : children;
|
|
||||||
}
|
|
||||||
const element = isClone ? type.type : type;
|
|
||||||
//合并默认属性
|
|
||||||
if (element && element.defaultProps) {
|
|
||||||
mergeDefault(props, element.defaultProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
return HorizonElement(element, key, ref, vNode, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
//创建Element结构体,供JSX编译时调用
|
|
||||||
export function createElement(type, setting, ...children) {
|
|
||||||
return buildElement(false, type, setting, ...children);
|
|
||||||
}
|
|
||||||
|
|
||||||
function mergeDefault(sourceObj, defaultObj) {
|
function mergeDefault(sourceObj, defaultObj) {
|
||||||
Object.keys(defaultObj).forEach((key) => {
|
Object.keys(defaultObj).forEach((key) => {
|
||||||
if (sourceObj[key] === undefined) {
|
if (sourceObj[key] === undefined) {
|
||||||
|
@ -72,11 +37,46 @@ function mergeDefault(sourceObj, defaultObj) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildElement(isClone, type, setting, ...children) {
|
||||||
|
// setting中的值优先级最高,clone情况下从 type 中取值,创建情况下直接赋值为 null
|
||||||
|
const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null);
|
||||||
|
const ref = (setting && setting.ref !== undefined) ? setting.ref : (isClone ? type.ref : null);
|
||||||
|
const props = isClone ? {...type.props} : {};
|
||||||
|
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
|
||||||
|
|
||||||
|
if (setting != null) {
|
||||||
|
Object.keys(setting).forEach(k => {
|
||||||
|
if (isValidKey(k)) {
|
||||||
|
props[k] = setting[k];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (setting.ref !== undefined && isClone) {
|
||||||
|
vNode = getProcessingClassVNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (children.length) {
|
||||||
|
props.children = children.length === 1 ? children[0] : children;
|
||||||
|
}
|
||||||
|
const element = isClone ? type.type : type;
|
||||||
|
// 合并默认属性
|
||||||
|
if (element && element.defaultProps) {
|
||||||
|
mergeDefault(props, element.defaultProps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return JSXElement(element, key, ref, vNode, props);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建Element结构体,供JSX编译时调用
|
||||||
|
export function createElement(type, setting, ...children) {
|
||||||
|
return buildElement(false, type, setting, ...children);
|
||||||
|
}
|
||||||
|
|
||||||
export function cloneElement(element, setting, ...children) {
|
export function cloneElement(element, setting, ...children) {
|
||||||
return buildElement(true, element, setting, ...children);
|
return buildElement(true, element, setting, ...children);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检测结构体是否为合法的Element
|
// 检测结构体是否为合法的Element
|
||||||
export function isValidElement(element) {
|
export function isValidElement(element) {
|
||||||
return !!(element && element.vtype === TYPE_ELEMENT);
|
return !!(element && element.vtype === TYPE_COMMON_ELEMENT);
|
||||||
}
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
export const TYPE_ELEMENT = 1;
|
export const TYPE_COMMON_ELEMENT = 1;
|
||||||
export const TYPE_PORTAL = 2;
|
export const TYPE_PORTAL = 2;
|
||||||
export const TYPE_FRAGMENT = 3;
|
export const TYPE_FRAGMENT = 3;
|
||||||
export const TYPE_STRICT_MODE = 4;
|
export const TYPE_STRICT_MODE = 4;
|
|
@ -5,7 +5,7 @@ export const InRender = 'IN_RENDER';
|
||||||
|
|
||||||
type RenderMode = typeof ByAsync | typeof BySync | typeof InRender;
|
type RenderMode = typeof ByAsync | typeof BySync | typeof InRender;
|
||||||
|
|
||||||
// 当前执行阶段标记
|
// 当前执行模式标记
|
||||||
let executeMode = {
|
let executeMode = {
|
||||||
[ByAsync]: false,
|
[ByAsync]: false,
|
||||||
[BySync]: false,
|
[BySync]: false,
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
import type {VNode} from './Types';
|
||||||
|
|
||||||
|
// 当前处理的classVNode,用于inst.refs用法中的
|
||||||
|
let processingClassVNode: VNode | null = null;
|
||||||
|
export function getProcessingClassVNode(): VNode | null {
|
||||||
|
return processingClassVNode;
|
||||||
|
}
|
||||||
|
export function setProcessingClassVNode(vNode: VNode | null) {
|
||||||
|
processingClassVNode = vNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算出来的刷新节点,不一定是根节点
|
||||||
|
let startVNode: VNode | null = null;
|
||||||
|
export function getStartVNode(): VNode | null {
|
||||||
|
return startVNode;
|
||||||
|
}
|
||||||
|
export function setStartVNode(vNode: VNode | null) {
|
||||||
|
startVNode = vNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
type BuildVNodeResult = 0 | 1 | 2 | 3;
|
||||||
|
export const BuildInComplete = 0;
|
||||||
|
export const BuildFatalErrored = 1;
|
||||||
|
export const BuildErrored = 2;
|
||||||
|
export const BuildCompleted = 3;
|
||||||
|
// 根节点退出build tree时的状态,如: completed, incomplete, errored, fatalErrored.
|
||||||
|
let buildVNodeResult: BuildVNodeResult = BuildInComplete;
|
||||||
|
export function setBuildResult(result: BuildVNodeResult) {
|
||||||
|
buildVNodeResult = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBuildResult(): BuildVNodeResult {
|
||||||
|
return buildVNodeResult;
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import type {VNode} from './Types';
|
import type { VNode } from './Types';
|
||||||
import type {Update} from './UpdateHandler';
|
import type { Update } from './UpdateHandler';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
asyncUpdates,
|
asyncUpdates,
|
||||||
|
@ -7,12 +7,12 @@ import {
|
||||||
runDiscreteUpdates,
|
runDiscreteUpdates,
|
||||||
launchUpdateFromVNode,
|
launchUpdateFromVNode,
|
||||||
} from './TreeBuilder';
|
} from './TreeBuilder';
|
||||||
import {runAsyncEffects} from './submit/HookEffectHandler';
|
import { runAsyncEffects } from './submit/HookEffectHandler';
|
||||||
import {Callback, newUpdate, pushUpdate} from './UpdateHandler';
|
import { Callback, newUpdate, pushUpdate } from './UpdateHandler';
|
||||||
import {getFirstChild} from './vnode/VNodeUtils';
|
import { getFirstChild } from './vnode/VNodeUtils';
|
||||||
|
|
||||||
export {createVNode} from './vnode/VNodeCreator';
|
export { createVNode } from './vnode/VNodeCreator';
|
||||||
export {createPortal} from './components/CreatePortal';
|
export { createPortal } from './components/CreatePortal';
|
||||||
export {
|
export {
|
||||||
asyncUpdates,
|
asyncUpdates,
|
||||||
syncUpdates,
|
syncUpdates,
|
||||||
|
@ -26,7 +26,7 @@ export function startUpdate(
|
||||||
callback?: Callback,
|
callback?: Callback,
|
||||||
) {
|
) {
|
||||||
const update: Update = newUpdate();
|
const update: Update = newUpdate();
|
||||||
update.content = {element};
|
update.content = { element };
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
update.callback = callback;
|
update.callback = callback;
|
||||||
|
@ -37,11 +37,10 @@ export function startUpdate(
|
||||||
launchUpdateFromVNode(treeRoot);
|
launchUpdateFromVNode(treeRoot);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFirstCustomDom(treeRoot: VNode): Element | Text | null {
|
export function getFirstCustomDom(treeRoot?: VNode | null): Element | Text | null {
|
||||||
if (!treeRoot.child) {
|
if (treeRoot?.child) {
|
||||||
return null;
|
return treeRoot.child.realNode;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
return treeRoot.child.realNode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,16 +1,24 @@
|
||||||
import type {VNode} from './Types';
|
import type { VNode } from './Types';
|
||||||
|
|
||||||
import {callRenderQueueImmediate, pushRenderCallback} from './taskExecutor/RenderQueue';
|
import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue';
|
||||||
import {updateVNode} from './vnode/VNodeCreator';
|
import { updateVNode } from './vnode/VNodeCreator';
|
||||||
import {TreeRoot} from './vnode/VNodeTags';
|
import { TreeRoot } from './vnode/VNodeTags';
|
||||||
import {FlagUtils} from './vnode/VNodeFlags';
|
import { FlagUtils } from './vnode/VNodeFlags';
|
||||||
import {captureVNode} from './render/BaseComponent';
|
import { captureVNode } from './render/BaseComponent';
|
||||||
import {checkLoopingUpdateLimit, submitToRender} from './submit/Submit';
|
import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit';
|
||||||
import {runAsyncEffects} from './submit/HookEffectHandler';
|
import { runAsyncEffects } from './submit/HookEffectHandler';
|
||||||
import {handleRenderThrowError} from './ErrorHandler';
|
import { handleRenderThrowError } from './ErrorHandler';
|
||||||
import componentRenders from './render';
|
import componentRenders from './render';
|
||||||
import ProcessingVNode from './vnode/ProcessingVNode';
|
import {
|
||||||
import {findDomParent, getSiblingVNode} from './vnode/VNodeUtils';
|
BuildCompleted, BuildErrored,
|
||||||
|
BuildFatalErrored,
|
||||||
|
BuildInComplete, getBuildResult,
|
||||||
|
getStartVNode,
|
||||||
|
setBuildResult,
|
||||||
|
setProcessingClassVNode,
|
||||||
|
setStartVNode
|
||||||
|
} from './GlobalVar';
|
||||||
|
import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils';
|
||||||
import {
|
import {
|
||||||
ByAsync,
|
ByAsync,
|
||||||
BySync,
|
BySync,
|
||||||
|
@ -21,172 +29,23 @@ import {
|
||||||
isExecuting,
|
isExecuting,
|
||||||
setExecuteMode
|
setExecuteMode
|
||||||
} from './ExecuteMode';
|
} from './ExecuteMode';
|
||||||
import {recoverParentsContextCtx, resetNamespaceCtx, setNamespaceCtx} from './ContextSaver';
|
import { recoverParentsContextCtx, resetNamespaceCtx, setNamespaceCtx } from './ContextSaver';
|
||||||
import {
|
import {
|
||||||
updateChildShouldUpdate,
|
updateChildShouldUpdate,
|
||||||
updateParentsChildShouldUpdate,
|
updateParentsChildShouldUpdate,
|
||||||
updateShouldUpdateOfTree
|
updateShouldUpdateOfTree
|
||||||
} from './vnode/VNodeShouldUpdate';
|
} from './vnode/VNodeShouldUpdate';
|
||||||
|
|
||||||
type BuildVNodeResult = 0 | 1 | 2 | 3;
|
|
||||||
const BuildInComplete = 0;
|
|
||||||
const BuildFatalErrored = 1;
|
|
||||||
const BuildErrored = 2;
|
|
||||||
const BuildCompleted = 3;
|
|
||||||
|
|
||||||
// 当前运行的vNode节点
|
// 当前运行的vNode节点
|
||||||
let processing: VNode | null = null;
|
let processing: VNode | null = null;
|
||||||
// 根节点退出build tree时的状态,如: completed, incomplete, errored, fatalErrored.
|
|
||||||
let buildVNodeResult: BuildVNodeResult = BuildInComplete;
|
|
||||||
// 不可恢复错误
|
// 不可恢复错误
|
||||||
let unrecoverableErrorDuringBuild: any = null;
|
let unrecoverableErrorDuringBuild: any = null;
|
||||||
|
|
||||||
function setBuildResult(result: BuildVNodeResult) {
|
|
||||||
buildVNodeResult = result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getBuildResult(): BuildVNodeResult {
|
|
||||||
return buildVNodeResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setProcessing(vNode: VNode | null) {
|
export function setProcessing(vNode: VNode | null) {
|
||||||
processing = vNode;
|
processing = vNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
let startVNode: VNode | null = null;
|
|
||||||
export function getStartVNode(): VNode | null {
|
|
||||||
return startVNode;
|
|
||||||
}
|
|
||||||
export function setStartVNode(vNode: VNode | null) {
|
|
||||||
startVNode = vNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发起更新
|
|
||||||
export function launchUpdateFromVNode(vNode: VNode) {
|
|
||||||
// 检查循环调用
|
|
||||||
checkLoopingUpdateLimit();
|
|
||||||
|
|
||||||
// 从当前vNode向上遍历到根节点,修改vNode.shouldUpdate和parent.childShouldUpdate
|
|
||||||
const treeRoot = updateShouldUpdateOfTree(vNode);
|
|
||||||
if (treeRoot === null) {
|
|
||||||
// 可能场景是:the componentWillUnmount method 或 useEffect cleanup function 方法中写异步任务,并且修改state。
|
|
||||||
// 因为异步回调的时候root都可能被清除了。
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存待刷新的节点
|
|
||||||
treeRoot.toUpdateNodes.add(vNode);
|
|
||||||
|
|
||||||
if (checkMode(BySync) && // 非批量
|
|
||||||
!checkMode(InRender)) { // 不是渲染阶段触发
|
|
||||||
|
|
||||||
// 业务直接调用Horizon.render的时候会进入这个分支,同步渲染。
|
|
||||||
// 不能改成下面的异步,否则会有时序问题,因为业务可能会依赖这个渲染的完成。
|
|
||||||
renderFromRoot(treeRoot);
|
|
||||||
} else {
|
|
||||||
tryRenderRoot(treeRoot);
|
|
||||||
|
|
||||||
if (!isExecuting()) {
|
|
||||||
// 同步执行
|
|
||||||
callRenderQueueImmediate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
|
||||||
export function calcStartUpdateVNode(treeRoot: VNode) {
|
|
||||||
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
|
|
||||||
|
|
||||||
if (toUpdateNodes.length === 0) {
|
|
||||||
return treeRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toUpdateNodes.length === 1) {
|
|
||||||
return toUpdateNodes[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 要计算的节点过多,直接返回根节点
|
|
||||||
if (toUpdateNodes.length > 100) {
|
|
||||||
return treeRoot;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找到路径最短的长度
|
|
||||||
let minPath = toUpdateNodes[0].path.length;
|
|
||||||
for (let i = 1; i < toUpdateNodes.length; i++) {
|
|
||||||
let pathLen = toUpdateNodes[i].path.length;
|
|
||||||
if (pathLen < minPath) {
|
|
||||||
minPath = pathLen;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找出开始不相等的idx
|
|
||||||
let idx = 0;
|
|
||||||
for (; idx < minPath; idx++) {
|
|
||||||
if (!isEqualByIndex(idx, toUpdateNodes)) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// 得到相等的路径
|
|
||||||
let startNodePath = toUpdateNodes[0].path.slice(0, idx);
|
|
||||||
|
|
||||||
let node = treeRoot;
|
|
||||||
for (let i = 1; i < startNodePath.length; i++) {
|
|
||||||
let pathIndex = startNodePath[i];
|
|
||||||
node = getChildByIndex(node, pathIndex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getChildByIndex(vNode: VNode, idx: number) {
|
|
||||||
let node = vNode.child;
|
|
||||||
for (let i = 0; i < idx; i++) {
|
|
||||||
node = node.next;
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 判断数组中节点的path的idx元素是否都相等
|
|
||||||
function isEqualByIndex(idx: number, nodes: Array<VNode>) {
|
|
||||||
let val = nodes[0].path[idx];
|
|
||||||
for (let i = 1; i < nodes.length; i++) {
|
|
||||||
let node = nodes[i];
|
|
||||||
if (val !== node.path[idx]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 尝试去渲染,已有任务就跳出
|
|
||||||
export function tryRenderRoot(treeRoot: VNode) {
|
|
||||||
if (treeRoot.shouldUpdate && treeRoot.task === null) {
|
|
||||||
// 任务放进queue,但是调度开始还是异步的
|
|
||||||
treeRoot.task = pushRenderCallback(
|
|
||||||
renderFromRoot.bind(null, treeRoot),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 总体任务入口
|
|
||||||
function renderFromRoot(treeRoot) {
|
|
||||||
runAsyncEffects();
|
|
||||||
|
|
||||||
// 1. 构建vNode树
|
|
||||||
buildVNodeTree(treeRoot);
|
|
||||||
|
|
||||||
// 致命错误直接抛出
|
|
||||||
if (getBuildResult() === BuildFatalErrored) {
|
|
||||||
throw unrecoverableErrorDuringBuild;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 提交变更
|
|
||||||
submitToRender(treeRoot);
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 为重新进行深度遍历做准备
|
// 为重新进行深度遍历做准备
|
||||||
function resetProcessingVariables(startUpdateVNode: VNode) {
|
function resetProcessingVariables(startUpdateVNode: VNode) {
|
||||||
// 创建processing
|
// 创建processing
|
||||||
|
@ -195,81 +54,13 @@ function resetProcessingVariables(startUpdateVNode: VNode) {
|
||||||
unrecoverableErrorDuringBuild = null;
|
unrecoverableErrorDuringBuild = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================== 深度遍历 ==============================
|
// 收集有变化的节点,在submit阶段继续处理
|
||||||
function buildVNodeTree(treeRoot: VNode) {
|
function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
||||||
const preMode = copyExecuteMode();
|
// 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。
|
||||||
changeMode(InRender, true);
|
parent.dirtyNodes.push(...vNode.dirtyNodes);
|
||||||
|
|
||||||
// 计算出开始节点
|
if (FlagUtils.hasAnyFlag(vNode)) {
|
||||||
const startUpdateVNode = calcStartUpdateVNode(treeRoot);
|
parent.dirtyNodes.push(vNode);
|
||||||
|
|
||||||
// 缓存起来
|
|
||||||
setStartVNode(startUpdateVNode);
|
|
||||||
|
|
||||||
// 清空toUpdateNodes
|
|
||||||
treeRoot.toUpdateNodes.clear();
|
|
||||||
|
|
||||||
if (startUpdateVNode.tag !== TreeRoot) { // 不是根节点
|
|
||||||
// 设置namespace,用于createElement
|
|
||||||
const parentObj = findDomParent(startUpdateVNode);
|
|
||||||
|
|
||||||
// 当在componentWillUnmount中调用setState,parent可能是null,因为startUpdateVNode会被clear
|
|
||||||
if (parentObj !== null) {
|
|
||||||
const domParent = parentObj.parent;
|
|
||||||
resetNamespaceCtx(domParent);
|
|
||||||
setNamespaceCtx(domParent, domParent.outerDom);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 恢复父节点的context
|
|
||||||
recoverParentsContextCtx(startUpdateVNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 重置环境变量
|
|
||||||
resetProcessingVariables(startUpdateVNode);
|
|
||||||
|
|
||||||
do {
|
|
||||||
try {
|
|
||||||
while (processing !== null) {
|
|
||||||
// 捕获创建 vNodes
|
|
||||||
const next = captureVNode(processing);
|
|
||||||
|
|
||||||
if (next === null) {
|
|
||||||
// 如果没有产生新的,那么就完成当前节点,向上遍历
|
|
||||||
bubbleVNode(processing);
|
|
||||||
} else {
|
|
||||||
processing = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
ProcessingVNode.val = null;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
} catch (thrownValue) {
|
|
||||||
handleError(treeRoot, thrownValue);
|
|
||||||
}
|
|
||||||
} while (true);
|
|
||||||
|
|
||||||
setExecuteMode(preMode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleError(root, error): void {
|
|
||||||
if (processing === null || processing.parent === null) {
|
|
||||||
// 这是一个致命的错误,因为没有祖先可以处理它
|
|
||||||
setBuildResult(BuildFatalErrored);
|
|
||||||
unrecoverableErrorDuringBuild = error;
|
|
||||||
|
|
||||||
processing = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理capture和bubble阶段抛出的错误
|
|
||||||
handleRenderThrowError(processing, error);
|
|
||||||
|
|
||||||
bubbleVNode(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setBuildResultError() {
|
|
||||||
if (getBuildResult() !== BuildCompleted) {
|
|
||||||
setBuildResult(BuildErrored);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -322,13 +113,207 @@ function bubbleVNode(vNode: VNode): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收集有变化的节点,在submit阶段继续处理
|
function handleError(root, error): void {
|
||||||
function collectDirtyNodes(vNode: VNode, parent: VNode): void {
|
if (processing === null || processing.parent === null) {
|
||||||
// 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。
|
// 这是一个致命的错误,因为没有祖先可以处理它
|
||||||
parent.dirtyNodes.push(...vNode.dirtyNodes);
|
setBuildResult(BuildFatalErrored);
|
||||||
|
unrecoverableErrorDuringBuild = error;
|
||||||
|
|
||||||
if (FlagUtils.hasAnyFlag(vNode)) {
|
processing = null;
|
||||||
parent.dirtyNodes.push(vNode);
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理capture和bubble阶段抛出的错误
|
||||||
|
handleRenderThrowError(processing, error);
|
||||||
|
|
||||||
|
bubbleVNode(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
|
||||||
|
export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||||
|
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
|
||||||
|
|
||||||
|
if (toUpdateNodes.length === 0) {
|
||||||
|
return treeRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (toUpdateNodes.length === 1) {
|
||||||
|
return toUpdateNodes[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
// 要计算的节点过多,直接返回根节点
|
||||||
|
if (toUpdateNodes.length > 100) {
|
||||||
|
return treeRoot;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找到路径最短的长度
|
||||||
|
let minPath = toUpdateNodes[0].path.length;
|
||||||
|
for (let i = 1; i < toUpdateNodes.length; i++) {
|
||||||
|
let pathLen = toUpdateNodes[i].path.length;
|
||||||
|
if (pathLen < minPath) {
|
||||||
|
minPath = pathLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 找出开始不相等的idx
|
||||||
|
let idx = 0;
|
||||||
|
for (; idx < minPath; idx++) {
|
||||||
|
if (!isEqualByIndex(idx, toUpdateNodes)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 得到相等的路径
|
||||||
|
let startNodePath = toUpdateNodes[0].path.slice(0, idx);
|
||||||
|
|
||||||
|
let node = treeRoot;
|
||||||
|
for (let i = 1; i < startNodePath.length; i++) {
|
||||||
|
let pathIndex = startNodePath[i];
|
||||||
|
node = getChildByIndex(node, pathIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================== 深度遍历 ==============================
|
||||||
|
function buildVNodeTree(treeRoot: VNode) {
|
||||||
|
const preMode = copyExecuteMode();
|
||||||
|
changeMode(InRender, true);
|
||||||
|
|
||||||
|
// 计算出开始节点
|
||||||
|
const startUpdateVNode = calcStartUpdateVNode(treeRoot);
|
||||||
|
// 缓存起来
|
||||||
|
setStartVNode(startUpdateVNode);
|
||||||
|
|
||||||
|
// 清空toUpdateNodes
|
||||||
|
treeRoot.toUpdateNodes.clear();
|
||||||
|
|
||||||
|
if (startUpdateVNode.tag !== TreeRoot) { // 不是根节点
|
||||||
|
// 设置namespace,用于createElement
|
||||||
|
const parentObj = findDomParent(startUpdateVNode);
|
||||||
|
|
||||||
|
// 当在componentWillUnmount中调用setState,parent可能是null,因为startUpdateVNode会被clear
|
||||||
|
if (parentObj !== null) {
|
||||||
|
const domParent = parentObj.parent;
|
||||||
|
resetNamespaceCtx(domParent);
|
||||||
|
setNamespaceCtx(domParent, domParent.outerDom);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 恢复父节点的context
|
||||||
|
recoverParentsContextCtx(startUpdateVNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 重置环境变量,为重新进行深度遍历做准备
|
||||||
|
resetProcessingVariables(startUpdateVNode);
|
||||||
|
|
||||||
|
do {
|
||||||
|
try {
|
||||||
|
while (processing !== null) {
|
||||||
|
// 捕获创建 vNodes
|
||||||
|
const next = captureVNode(processing);
|
||||||
|
|
||||||
|
if (next === null) {
|
||||||
|
// 如果没有产生新的,那么就完成当前节点,向上遍历
|
||||||
|
bubbleVNode(processing);
|
||||||
|
} else {
|
||||||
|
processing = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setProcessingClassVNode(null);
|
||||||
|
|
||||||
|
break;
|
||||||
|
} catch (thrownValue) {
|
||||||
|
handleError(treeRoot, thrownValue);
|
||||||
|
}
|
||||||
|
} while (true);
|
||||||
|
|
||||||
|
setExecuteMode(preMode);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总体任务入口
|
||||||
|
function renderFromRoot(treeRoot) {
|
||||||
|
runAsyncEffects();
|
||||||
|
|
||||||
|
// 1. 构建vNode树
|
||||||
|
buildVNodeTree(treeRoot);
|
||||||
|
|
||||||
|
// 致命错误直接抛出
|
||||||
|
if (getBuildResult() === BuildFatalErrored) {
|
||||||
|
throw unrecoverableErrorDuringBuild;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 提交变更
|
||||||
|
submitToRender(treeRoot);
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 尝试去渲染,已有任务就跳出
|
||||||
|
export function tryRenderRoot(treeRoot: VNode) {
|
||||||
|
if (treeRoot.shouldUpdate && treeRoot.task === null) {
|
||||||
|
// 任务放进queue,但是调度开始还是异步的
|
||||||
|
treeRoot.task = pushRenderCallback(
|
||||||
|
renderFromRoot.bind(null, treeRoot),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 发起更新
|
||||||
|
export function launchUpdateFromVNode(vNode: VNode) {
|
||||||
|
// 检查循环调用
|
||||||
|
checkLoopingUpdateLimit();
|
||||||
|
|
||||||
|
// 从当前vNode向上遍历到根节点,修改vNode.shouldUpdate和parent.childShouldUpdate
|
||||||
|
const treeRoot = updateShouldUpdateOfTree(vNode);
|
||||||
|
if (treeRoot === null) {
|
||||||
|
// 可能场景是:the componentWillUnmount method 或 useEffect cleanup function 方法中写异步任务,并且修改state。
|
||||||
|
// 因为异步回调的时候root都可能被清除了。
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存待刷新的节点
|
||||||
|
treeRoot.toUpdateNodes.add(vNode);
|
||||||
|
|
||||||
|
if (checkMode(BySync) && // 非批量
|
||||||
|
!checkMode(InRender)) { // 不是渲染阶段触发
|
||||||
|
|
||||||
|
// 业务直接调用Horizon.render的时候会进入这个分支,同步渲染。
|
||||||
|
// 不能改成下面的异步,否则会有时序问题,因为业务可能会依赖这个渲染的完成。
|
||||||
|
renderFromRoot(treeRoot);
|
||||||
|
} else {
|
||||||
|
tryRenderRoot(treeRoot);
|
||||||
|
|
||||||
|
if (!isExecuting()) {
|
||||||
|
// 同步执行
|
||||||
|
callRenderQueueImmediate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断数组中节点的path的idx元素是否都相等
|
||||||
|
function isEqualByIndex(idx: number, nodes: Array<VNode>) {
|
||||||
|
let val = nodes[0].path[idx];
|
||||||
|
for (let i = 1; i < nodes.length; i++) {
|
||||||
|
let node = nodes[i];
|
||||||
|
if (val !== node.path[idx]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChildByIndex(vNode: VNode, idx: number) {
|
||||||
|
let node = vNode.child;
|
||||||
|
for (let i = 0; i < idx; i++) {
|
||||||
|
node = node.next;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setBuildResultError() {
|
||||||
|
if (getBuildResult() !== BuildCompleted) {
|
||||||
|
setBuildResult(BuildErrored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,28 +2,27 @@ export { VNode } from './vnode/VNode';
|
||||||
|
|
||||||
type Trigger<A> = (A) => void;
|
type Trigger<A> = (A) => void;
|
||||||
|
|
||||||
export type ReadContextHookType = { readContext<T>(context: ContextType<T>): T };
|
|
||||||
export type UseStateHookType = {
|
export type UseStateHookType = {
|
||||||
useState<S>(
|
useState<S>(
|
||||||
initialState: (() => S) | S
|
initialState: (() => S) | S
|
||||||
): [S, Trigger<((S) => S) | S>]
|
): [S, Trigger<((S) => S) | S>];
|
||||||
};
|
};
|
||||||
export type UseReducerHookType = {
|
export type UseReducerHookType = {
|
||||||
useReducer<S, P, A>(
|
useReducer<S, P, A>(
|
||||||
reducer: (S, A) => S,
|
reducer: (S, A) => S,
|
||||||
initArg: P, init?: (P) => S,
|
initArg: P, init?: (P) => S,
|
||||||
): [S, Trigger<A>]
|
): [S, Trigger<A>];
|
||||||
};
|
};
|
||||||
export type UseContextHookType = { useContext<T>(context: ContextType<T>,): T };
|
export type UseContextHookType = { useContext<T>(context: ContextType<T>,): T };
|
||||||
|
|
||||||
export type HorizonElement = {
|
export type JSXElement = {
|
||||||
vtype: any,
|
vtype: any;
|
||||||
type: any,
|
type: any;
|
||||||
key: any,
|
key: any;
|
||||||
ref: any,
|
ref: any;
|
||||||
props: any,
|
props: any;
|
||||||
|
|
||||||
_vNode: any,
|
belongClassVNode: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type ProviderType<T> = {
|
export type ProviderType<T> = {
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
import type {VNode} from './Types';
|
import type { VNode } from './Types';
|
||||||
import {FlagUtils, ShouldCapture} from './vnode/VNodeFlags';
|
import { FlagUtils, ShouldCapture } from './vnode/VNodeFlags';
|
||||||
|
|
||||||
export type Update = {
|
export type Update = {
|
||||||
type: 'Update' | 'Override' | 'ForceUpdate' | 'Error',
|
type: 'Update' | 'Override' | 'ForceUpdate' | 'Error';
|
||||||
content: any,
|
content: any;
|
||||||
callback: Callback | null,
|
callback: Callback | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Callback = () => any;
|
export type Callback = () => any;
|
||||||
|
@ -35,11 +35,8 @@ export function newUpdate(): Update {
|
||||||
// 将update对象加入updates
|
// 将update对象加入updates
|
||||||
export function pushUpdate(vNode: VNode, update: Update) {
|
export function pushUpdate(vNode: VNode, update: Update) {
|
||||||
const updates = vNode.updates;
|
const updates = vNode.updates;
|
||||||
if (updates === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
updates.push(update);
|
updates?.push(update);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据update获取新的state
|
// 根据update获取新的state
|
||||||
|
@ -50,24 +47,25 @@ function calcState(
|
||||||
oldState: any,
|
oldState: any,
|
||||||
props: any,
|
props: any,
|
||||||
): any {
|
): any {
|
||||||
if (update.type === UpdateState.Override) {
|
switch (update.type) {
|
||||||
const content = update.content;
|
case UpdateState.Override:
|
||||||
return typeof content === 'function' ? content.call(inst, oldState, props) : content;
|
const content = update.content;
|
||||||
} else if (update.type === UpdateState.ForceUpdate) {
|
return typeof content === 'function' ? content.call(inst, oldState, props) : content;
|
||||||
vNode.isForceUpdate = true;
|
case UpdateState.ForceUpdate:
|
||||||
return oldState;
|
vNode.isForceUpdate = true;
|
||||||
} else if (update.type === UpdateState.Error || update.type === UpdateState.Update) {
|
return oldState;
|
||||||
if (update.type === UpdateState.Error) {
|
case UpdateState.Error:
|
||||||
FlagUtils.removeFlag(vNode, ShouldCapture);
|
FlagUtils.removeFlag(vNode, ShouldCapture);
|
||||||
FlagUtils.markDidCapture(vNode);
|
FlagUtils.markDidCapture(vNode);
|
||||||
}
|
case UpdateState.Update:
|
||||||
const content = update.content;
|
const updateContent = update.content;
|
||||||
const newState = typeof content === 'function' ? content.call(inst, oldState, props) : content;
|
const newState = typeof updateContent === 'function' ? updateContent.call(inst, oldState, props) : updateContent;
|
||||||
return (newState === null || newState === undefined)
|
return (newState === null || newState === undefined)
|
||||||
? oldState
|
? oldState
|
||||||
: {...oldState, ...newState}
|
: { ...oldState, ...newState };
|
||||||
|
default:
|
||||||
|
return oldState;
|
||||||
}
|
}
|
||||||
return oldState;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收集callback
|
// 收集callback
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
import {TYPE_PORTAL} from '../utils/elementType';
|
import {TYPE_PORTAL} from '../../external/JSXElementType';
|
||||||
import type {PortalType} from '../Types';
|
import type {PortalType} from '../Types';
|
||||||
|
|
||||||
export function createPortal(
|
export function createPortal(
|
||||||
children: any,
|
children: any,
|
||||||
outerDom: any,
|
outerDom: any,
|
||||||
key: string = null,
|
key: string = '',
|
||||||
): PortalType {
|
): PortalType {
|
||||||
return {
|
return {
|
||||||
vtype: TYPE_PORTAL,
|
vtype: TYPE_PORTAL,
|
||||||
key: key == null ? null : '' + key,
|
key: key == '' ? '' : '' + key,
|
||||||
children,
|
children,
|
||||||
outerDom,
|
outerDom,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {TYPE_FORWARD_REF} from '../utils/elementType';
|
import {TYPE_FORWARD_REF} from '../../external/JSXElementType';
|
||||||
|
|
||||||
export function forwardRef(render: Function) {
|
export function forwardRef(render: Function) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type {PromiseType} from '../Types';
|
import type {PromiseType} from '../Types';
|
||||||
|
|
||||||
import {TYPE_LAZY} from '../utils/elementType';
|
import {TYPE_LAZY} from '../../external/JSXElementType';
|
||||||
|
|
||||||
enum LayStatus {
|
enum LayStatus {
|
||||||
UnProcessed = 'UnProcessed',
|
UnProcessed = 'UnProcessed',
|
||||||
|
@ -10,14 +10,14 @@ enum LayStatus {
|
||||||
}
|
}
|
||||||
|
|
||||||
type LazyContent<T> = {
|
type LazyContent<T> = {
|
||||||
_status: string,
|
_status: string;
|
||||||
_value: () => PromiseType<{default: T}> | PromiseType<T> | T | any
|
_value: () => PromiseType<{default: T}> | PromiseType<T> | T | any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type LazyComponent<T, P> = {
|
export type LazyComponent<T, P> = {
|
||||||
vtype: number,
|
vtype: number;
|
||||||
_content: P,
|
_content: P;
|
||||||
_load: (content: P) => T,
|
_load: (content: P) => T;
|
||||||
};
|
};
|
||||||
|
|
||||||
// lazyContent随着阶段改变,_value改变:
|
// lazyContent随着阶段改变,_value改变:
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import {TYPE_MEMO} from '../utils/elementType';
|
import {TYPE_MEMO} from '../../external/JSXElementType';
|
||||||
|
|
||||||
export function memo<Props>(type, compare?: (oldProps: Props, newProps: Props) => boolean) {
|
export function memo<Props>(type, compare?: (oldProps: Props, newProps: Props) => boolean) {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -51,7 +51,7 @@ export function getOldContext(processing: VNode, clazz: Function, ifProvider: bo
|
||||||
|
|
||||||
// 当组件既是提供者,也是消费者时,取上一个context,不能直接取最新context,因为已经被更新为当前组件的context;
|
// 当组件既是提供者,也是消费者时,取上一个context,不能直接取最新context,因为已经被更新为当前组件的context;
|
||||||
// 当组件只是消费者时,则取最新context
|
// 当组件只是消费者时,则取最新context
|
||||||
const parentContext = ((ifProvider && isOldProvider(clazz))) ?
|
const parentContext = (ifProvider && isOldProvider(clazz)) ?
|
||||||
getOldPreviousContextCtx() :
|
getOldPreviousContextCtx() :
|
||||||
getOldContextCtx();
|
getOldContextCtx();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import type {ContextType} from '../../Types';
|
import type {ContextType} from '../../Types';
|
||||||
import {TYPE_PROVIDER, TYPE_CONTEXT} from '../../utils/elementType';
|
import {TYPE_PROVIDER, TYPE_CONTEXT} from '../../../external/JSXElementType';
|
||||||
|
|
||||||
export function createContext<T>(val: T): ContextType<T> {
|
export function createContext<T>(val: T): ContextType<T> {
|
||||||
const context: ContextType<T> = {
|
const context: ContextType<T> = {
|
||||||
|
|
|
@ -1,27 +1,11 @@
|
||||||
import type { VNode, HorizonElement } from '../Types';
|
import type { VNode, JSXElement } from '../Types';
|
||||||
|
|
||||||
// 当前vNode和element是同样的类型
|
// 当前vNode和element是同样的类型
|
||||||
// LazyComponent 会修改type的类型,所以特殊处理这种类型
|
// LazyComponent 会修改type的类型,所以特殊处理这种类型
|
||||||
export const isSameType = (vNode: VNode, ele: HorizonElement) => {
|
export const isSameType = (vNode: VNode, ele: JSXElement) => {
|
||||||
return vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type);
|
return vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function createRef(element: HorizonElement) {
|
|
||||||
const elementRef = element.ref;
|
|
||||||
// 如果ref是null、function、object,直接返回
|
|
||||||
if (elementRef === null || typeof elementRef === 'function' || typeof elementRef === 'object') {
|
|
||||||
return elementRef;
|
|
||||||
} else { // 包装成函数
|
|
||||||
if (element._vNode) {
|
|
||||||
let inst = element._vNode.realNode;
|
|
||||||
|
|
||||||
return function(instance) {
|
|
||||||
inst.refs[String(elementRef)] = instance;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isTextType(newChild: any) {
|
export function isTextType(newChild: any) {
|
||||||
return typeof newChild === 'string' || typeof newChild === 'number';
|
return typeof newChild === 'string' || typeof newChild === 'number';
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,10 @@
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { TYPE_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../utils/elementType';
|
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType';
|
||||||
import { DomText, DomPortal, Fragment } from '../vnode/VNodeTags';
|
import { DomText, DomPortal, Fragment } from '../vnode/VNodeTags';
|
||||||
import {updateVNode, createVNode, createVNodeFromElement, updateVNodePath} from '../vnode/VNodeCreator';
|
import {updateVNode, createVNode, createVNodeFromElement, updateVNodePath} from '../vnode/VNodeCreator';
|
||||||
import {
|
import {
|
||||||
isSameType,
|
isSameType,
|
||||||
createRef,
|
|
||||||
getIteratorFn,
|
getIteratorFn,
|
||||||
isTextType,
|
isTextType,
|
||||||
isArrayType,
|
isArrayType,
|
||||||
|
@ -60,7 +59,7 @@ function checkCanReuseNode(oldNode: VNode | null, newChild: any): boolean {
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
||||||
return oldKey === null;
|
return oldKey === null;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
return oldKey === newChild.key;
|
return oldKey === newChild.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -79,7 +78,7 @@ function getNodeType(newChild: any): string {
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
||||||
return DiffCategory.ARR_NODE;
|
return DiffCategory.ARR_NODE;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
return DiffCategory.OBJECT_NODE;
|
return DiffCategory.OBJECT_NODE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -129,7 +128,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case DiffCategory.OBJECT_NODE: {
|
case DiffCategory.OBJECT_NODE: {
|
||||||
if (newChild.vtype === TYPE_ELEMENT) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT) {
|
||||||
if (newChild.type === TYPE_FRAGMENT) {
|
if (newChild.type === TYPE_FRAGMENT) {
|
||||||
if (oldNode === null || oldNode.tag !== Fragment) {
|
if (oldNode === null || oldNode.tag !== Fragment) {
|
||||||
const key = oldNode !== null ? oldNode.key : newChild.key;
|
const key = oldNode !== null ? oldNode.key : newChild.key;
|
||||||
|
@ -142,10 +141,12 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
|
||||||
|
|
||||||
if (oldNode === null || !isSameType(oldNode, newChild)) {
|
if (oldNode === null || !isSameType(oldNode, newChild)) {
|
||||||
resultNode = createVNodeFromElement(newChild);
|
resultNode = createVNodeFromElement(newChild);
|
||||||
resultNode.ref = createRef(newChild);
|
resultNode.ref = newChild.ref;
|
||||||
|
resultNode.belongClassVNode = newChild.belongClassVNode;
|
||||||
} else {
|
} else {
|
||||||
resultNode = updateVNode(oldNode, newChild.props);
|
resultNode = updateVNode(oldNode, newChild.props);
|
||||||
resultNode.ref = createRef(newChild);
|
resultNode.ref = newChild.ref;
|
||||||
|
resultNode.belongClassVNode = newChild.belongClassVNode;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else if (newChild.vtype === TYPE_PORTAL) {
|
} else if (newChild.vtype === TYPE_PORTAL) {
|
||||||
|
@ -200,7 +201,7 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
||||||
return nodeMap.get(newIdx) || null;
|
return nodeMap.get(newIdx) || null;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
return nodeMap.get(newChild.key === null ? newIdx : newChild.key) || null;
|
return nodeMap.get(newChild.key === null ? newIdx : newChild.key) || null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -354,9 +355,9 @@ function diffArrayNodes(
|
||||||
// 把剩下的currentVNode转成Map
|
// 把剩下的currentVNode转成Map
|
||||||
const leftChildrenMap = transLeftChildrenToMap(oldNode, rightEndOldNode);
|
const leftChildrenMap = transLeftChildrenToMap(oldNode, rightEndOldNode);
|
||||||
// 通过贪心算法+二分法获取最长递增子序列
|
// 通过贪心算法+二分法获取最长递增子序列
|
||||||
const eIndexes = []; // 记录 eIndex 值
|
const eIndexes: Array<number> = []; // 记录 eIndex 值
|
||||||
const result = []; // 记录最长子序列在eIndexes中的 index 值
|
const result: Array<number> = []; // 记录最长子序列在eIndexes中的 index 值
|
||||||
const preIndex = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
||||||
const reuseNodes = []; // 记录复用的 VNode
|
const reuseNodes = []; // 记录复用的 VNode
|
||||||
let i = 0;
|
let i = 0;
|
||||||
for (; leftIdx < rightIdx; leftIdx++) {
|
for (; leftIdx < rightIdx; leftIdx++) {
|
||||||
|
@ -367,6 +368,7 @@ function diffArrayNodes(
|
||||||
// 从Map删除,后面不会deleteVNode
|
// 从Map删除,后面不会deleteVNode
|
||||||
leftChildrenMap.delete(newNode.key || leftIdx);
|
leftChildrenMap.delete(newNode.key || leftIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oldNodeFromMap !== null) {
|
if (oldNodeFromMap !== null) {
|
||||||
let eIndex = newNode.eIndex;
|
let eIndex = newNode.eIndex;
|
||||||
eIndexes.push(eIndex);
|
eIndexes.push(eIndex);
|
||||||
|
@ -380,7 +382,7 @@ function diffArrayNodes(
|
||||||
let middle;
|
let middle;
|
||||||
// 二分法找到需要替换的值
|
// 二分法找到需要替换的值
|
||||||
while (start < end) {
|
while (start < end) {
|
||||||
middle = Math.floor((start + end) / 2)
|
middle = Math.floor((start + end) / 2);
|
||||||
if (eIndexes[result[middle]] > eIndex) {
|
if (eIndexes[result[middle]] > eIndex) {
|
||||||
end = middle;
|
end = middle;
|
||||||
} else {
|
} else {
|
||||||
|
@ -403,6 +405,7 @@ function diffArrayNodes(
|
||||||
appendNode(newNode);
|
appendNode(newNode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isComparing) {
|
if (isComparing) {
|
||||||
// 向前回溯找到正确的结果
|
// 向前回溯找到正确的结果
|
||||||
let length = result.length;
|
let length = result.length;
|
||||||
|
@ -411,9 +414,9 @@ function diffArrayNodes(
|
||||||
result[length] = prev;
|
result[length] = prev;
|
||||||
prev = preIndex[result[length]];
|
prev = preIndex[result[length]];
|
||||||
}
|
}
|
||||||
result.forEach(i => {
|
result.forEach(idx => {
|
||||||
// 把需要复用的节点从 restNodes 中清理掉,因为不需要打 add 标记,直接复用 dom 节点
|
// 把需要复用的节点从 restNodes 中清理掉,因为不需要打 add 标记,直接复用 dom 节点
|
||||||
reuseNodes[i] = null;
|
reuseNodes[idx] = null;
|
||||||
});
|
});
|
||||||
reuseNodes.forEach(node => {
|
reuseNodes.forEach(node => {
|
||||||
if (node !== null) {
|
if (node !== null) {
|
||||||
|
@ -490,7 +493,7 @@ function diffStringNodeHandler(
|
||||||
firstChildVNode: VNode,
|
firstChildVNode: VNode,
|
||||||
isComparing: boolean
|
isComparing: boolean
|
||||||
) {
|
) {
|
||||||
let newTextNode = null;
|
let newTextNode: VNode | null = null;
|
||||||
|
|
||||||
// 第一个vNode是Text,则复用
|
// 第一个vNode是Text,则复用
|
||||||
if (firstChildVNode !== null && firstChildVNode.tag === DomText) {
|
if (firstChildVNode !== null && firstChildVNode.tag === DomText) {
|
||||||
|
@ -520,7 +523,7 @@ function diffObjectNodeHandler(
|
||||||
firstChildVNode: VNode,
|
firstChildVNode: VNode,
|
||||||
isComparing: boolean
|
isComparing: boolean
|
||||||
) {
|
) {
|
||||||
let canReuseNode = null;
|
let canReuseNode: VNode | null = null;
|
||||||
|
|
||||||
// 通过key比对是否有可以reuse
|
// 通过key比对是否有可以reuse
|
||||||
const newKey = newChild.key;
|
const newKey = newChild.key;
|
||||||
|
@ -535,9 +538,9 @@ function diffObjectNodeHandler(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let resultNode = null;
|
let resultNode: VNode | null = null;
|
||||||
let startDelVNode = firstChildVNode;
|
let startDelVNode = firstChildVNode;
|
||||||
if (newChild.vtype === TYPE_ELEMENT) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT) {
|
||||||
if (canReuseNode) {
|
if (canReuseNode) {
|
||||||
// 可以复用
|
// 可以复用
|
||||||
if (canReuseNode.tag === Fragment && newChild.type === TYPE_FRAGMENT) {
|
if (canReuseNode.tag === Fragment && newChild.type === TYPE_FRAGMENT) {
|
||||||
|
@ -546,7 +549,8 @@ function diffObjectNodeHandler(
|
||||||
resultNode.next = null;
|
resultNode.next = null;
|
||||||
} else if (isSameType(canReuseNode, newChild)) {
|
} else if (isSameType(canReuseNode, newChild)) {
|
||||||
resultNode = updateVNode(canReuseNode, newChild.props);
|
resultNode = updateVNode(canReuseNode, newChild.props);
|
||||||
resultNode.ref = createRef(newChild);
|
resultNode.ref = newChild.ref;
|
||||||
|
resultNode.belongClassVNode = newChild.belongClassVNode;
|
||||||
startDelVNode = getSiblingVNode(resultNode);
|
startDelVNode = getSiblingVNode(resultNode);
|
||||||
resultNode.next = null;
|
resultNode.next = null;
|
||||||
}
|
}
|
||||||
|
@ -558,7 +562,8 @@ function diffObjectNodeHandler(
|
||||||
resultNode = createVNode(Fragment, newChild.key, newChild.props.children);
|
resultNode = createVNode(Fragment, newChild.key, newChild.props.children);
|
||||||
} else {
|
} else {
|
||||||
resultNode = createVNodeFromElement(newChild);
|
resultNode = createVNodeFromElement(newChild);
|
||||||
resultNode.ref = createRef(newChild);
|
resultNode.ref = newChild.ref;
|
||||||
|
resultNode.belongClassVNode = newChild.belongClassVNode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (newChild.vtype === TYPE_PORTAL) {
|
} else if (newChild.vtype === TYPE_PORTAL) {
|
||||||
|
|
|
@ -4,7 +4,7 @@ export enum HookStage {
|
||||||
Update = 2,
|
Update = 2,
|
||||||
}
|
}
|
||||||
|
|
||||||
let hookStage: HookStage = null;
|
let hookStage: HookStage | null = null;
|
||||||
|
|
||||||
export function getHookStage() {
|
export function getHookStage() {
|
||||||
return hookStage;
|
return hookStage;
|
||||||
|
|
|
@ -31,9 +31,9 @@ function useEffect(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stage === HookStage.Init) {
|
if (stage === HookStage.Init) {
|
||||||
return useEffectForInit(effectFunc, deps, effectType);
|
useEffectForInit(effectFunc, deps, effectType);
|
||||||
} else if (stage === HookStage.Update) {
|
} else if (stage === HookStage.Update) {
|
||||||
return useEffectForUpdate(effectFunc, deps, effectType);
|
useEffectForUpdate(effectFunc, deps, effectType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,32 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||||
import componentRenders from './index';
|
import componentRenders from './index';
|
||||||
|
|
||||||
|
// 复用vNode时,也需对stack进行处理
|
||||||
|
function handlerContext(processing: VNode) {
|
||||||
|
switch (processing.tag) {
|
||||||
|
case TreeRoot:
|
||||||
|
setNamespaceCtx(processing, processing.outerDom);
|
||||||
|
break;
|
||||||
|
case DomComponent:
|
||||||
|
setNamespaceCtx(processing);
|
||||||
|
break;
|
||||||
|
case ClassComponent: {
|
||||||
|
const isOldCxtExist = isOldProvider(processing.type);
|
||||||
|
cacheOldCtx(processing, isOldCxtExist);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case DomPortal:
|
||||||
|
setNamespaceCtx(processing, processing.outerDom);
|
||||||
|
break;
|
||||||
|
case ContextProvider: {
|
||||||
|
const newValue = processing.props.value;
|
||||||
|
setContextCtx(processing, newValue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// No Default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function captureVNode(processing: VNode): VNode | null {
|
export function captureVNode(processing: VNode): VNode | null {
|
||||||
const component = componentRenders[processing.tag];
|
const component = componentRenders[processing.tag];
|
||||||
|
|
||||||
|
@ -38,31 +64,6 @@ export function captureVNode(processing: VNode): VNode | null {
|
||||||
return component.captureRender(processing, shouldUpdate);
|
return component.captureRender(processing, shouldUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 复用vNode时,也需对stack进行处理
|
|
||||||
function handlerContext(processing: VNode) {
|
|
||||||
switch (processing.tag) {
|
|
||||||
case TreeRoot:
|
|
||||||
setNamespaceCtx(processing, processing.outerDom);
|
|
||||||
break;
|
|
||||||
case DomComponent:
|
|
||||||
setNamespaceCtx(processing);
|
|
||||||
break;
|
|
||||||
case ClassComponent: {
|
|
||||||
const isOldCxtExist = isOldProvider(processing.type);
|
|
||||||
cacheOldCtx(processing, isOldCxtExist);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case DomPortal:
|
|
||||||
setNamespaceCtx(processing, processing.outerDom);
|
|
||||||
break;
|
|
||||||
case ContextProvider: {
|
|
||||||
const newValue = processing.props.value;
|
|
||||||
setContextCtx(processing, newValue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建孩子节点
|
// 创建孩子节点
|
||||||
export function createVNodeChildren(processing: VNode, nextChildren: any) {
|
export function createVNodeChildren(processing: VNode, nextChildren: any) {
|
||||||
const isComparing = !processing.isCreated;
|
const isComparing = !processing.isCreated;
|
||||||
|
|
|
@ -20,33 +20,88 @@ import {
|
||||||
markComponentDidUpdate,
|
markComponentDidUpdate,
|
||||||
markGetSnapshotBeforeUpdate,
|
markGetSnapshotBeforeUpdate,
|
||||||
} from './class/ClassLifeCycleProcessor';
|
} from './class/ClassLifeCycleProcessor';
|
||||||
import {FlagUtils} from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { createVNodeChildren, markRef } from './BaseComponent';
|
import { createVNodeChildren, markRef } from './BaseComponent';
|
||||||
import {
|
import {
|
||||||
createUpdateArray,
|
createUpdateArray,
|
||||||
processUpdates,
|
processUpdates,
|
||||||
} from '../UpdateHandler';
|
} from '../UpdateHandler';
|
||||||
import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver';
|
import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver';
|
||||||
import ProcessingVNode from '../vnode/ProcessingVNode';
|
import { setProcessingClassVNode } from '../GlobalVar';
|
||||||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
// 获取当前节点的context
|
||||||
const clazz = processing.type;
|
export function getCurrentContext(clazz, processing: VNode) {
|
||||||
const props = processing.props;
|
const context = clazz.contextType;
|
||||||
const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props;
|
return typeof context === 'object' && context !== null
|
||||||
return captureClassComponent(processing, clazz, nextProps);
|
? getNewContext(processing, context)
|
||||||
|
: getOldContext(processing, clazz, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
// 挂载实例
|
||||||
if (isOldProvider(processing.type)) {
|
function mountInstance(clazz, processing: VNode, nextProps: object) {
|
||||||
resetOldCtx(processing);
|
if (!processing.isCreated) {
|
||||||
|
processing.isCreated = true;
|
||||||
|
FlagUtils.markAddition(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构造实例
|
||||||
|
callConstructor(processing, clazz, nextProps);
|
||||||
|
|
||||||
|
const inst = processing.realNode;
|
||||||
|
inst.props = nextProps;
|
||||||
|
inst.state = processing.state;
|
||||||
|
inst.context = getCurrentContext(clazz, processing);
|
||||||
|
inst.refs = {};
|
||||||
|
|
||||||
|
createUpdateArray(processing);
|
||||||
|
processUpdates(processing, inst, nextProps);
|
||||||
|
inst.state = processing.state;
|
||||||
|
|
||||||
|
// 在调用类组建的渲染方法之前调用 并且在初始挂载及后续更新时都会被调用
|
||||||
|
callDerivedStateFromProps(processing, clazz.getDerivedStateFromProps, nextProps);
|
||||||
|
callComponentWillMount(processing, inst, nextProps);
|
||||||
|
|
||||||
|
markComponentDidMount(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 构建子节点
|
||||||
|
function createChildren(clazz: any, processing: VNode) {
|
||||||
|
markRef(processing);
|
||||||
|
|
||||||
|
setProcessingClassVNode(processing);
|
||||||
|
processing.state = processing.realNode.state;
|
||||||
|
|
||||||
|
const inst = processing.realNode;
|
||||||
|
const isCatchError = processing.flags.DidCapture;
|
||||||
|
|
||||||
|
// 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null
|
||||||
|
const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function'
|
||||||
|
? null
|
||||||
|
: inst.render();
|
||||||
|
|
||||||
|
processing.child = createVNodeChildren(processing, newElements);
|
||||||
|
return processing.child;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 根据isUpdateComponent,执行不同的生命周期
|
||||||
|
function callUpdateLifeCycle(processing: VNode, nextProps: object, clazz) {
|
||||||
|
const inst = processing.realNode;
|
||||||
|
const newContext = getCurrentContext(clazz, processing);
|
||||||
|
if (processing.isCreated) {
|
||||||
|
callComponentWillMount(processing, inst);
|
||||||
|
} else {
|
||||||
|
callComponentWillUpdate(inst, nextProps, processing.state, newContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用于未完成的类组件
|
function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) {
|
||||||
export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object):VNode | null {
|
if (processing.isCreated) {
|
||||||
mountInstance(clazz, processing, nextProps);
|
markComponentDidMount(processing);
|
||||||
return createChildren(clazz, processing);
|
} else if (processing.state !== processing.oldState || shouldUpdate) {
|
||||||
|
markComponentDidUpdate(processing);
|
||||||
|
markGetSnapshotBeforeUpdate(processing);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用于类组件
|
// 用于类组件
|
||||||
|
@ -127,76 +182,21 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 挂载实例
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
function mountInstance(clazz, processing: VNode, nextProps: object) {
|
const clazz = processing.type;
|
||||||
if (!processing.isCreated) {
|
const props = processing.props;
|
||||||
processing.isCreated = true;
|
const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props;
|
||||||
FlagUtils.markAddition(processing);
|
return captureClassComponent(processing, clazz, nextProps);
|
||||||
}
|
|
||||||
|
|
||||||
// 构造实例
|
|
||||||
callConstructor(processing, clazz, nextProps);
|
|
||||||
|
|
||||||
const inst = processing.realNode;
|
|
||||||
inst.props = nextProps;
|
|
||||||
inst.state = processing.state;
|
|
||||||
inst.context = getCurrentContext(clazz, processing);
|
|
||||||
inst.refs = {};
|
|
||||||
|
|
||||||
createUpdateArray(processing);
|
|
||||||
processUpdates(processing, inst, nextProps);
|
|
||||||
inst.state = processing.state;
|
|
||||||
|
|
||||||
// 在调用类组建的渲染方法之前调用 并且在初始挂载及后续更新时都会被调用
|
|
||||||
callDerivedStateFromProps(processing, clazz.getDerivedStateFromProps, nextProps);
|
|
||||||
callComponentWillMount(processing, inst, nextProps);
|
|
||||||
|
|
||||||
markComponentDidMount(processing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 构建子节点
|
export function bubbleRender(processing: VNode) {
|
||||||
function createChildren(clazz: any, processing: VNode) {
|
if (isOldProvider(processing.type)) {
|
||||||
markRef(processing);
|
resetOldCtx(processing);
|
||||||
|
|
||||||
ProcessingVNode.val = processing;
|
|
||||||
processing.state = processing.realNode.state;
|
|
||||||
|
|
||||||
const inst = processing.realNode;
|
|
||||||
const isCatchError = processing.flags.DidCapture;
|
|
||||||
|
|
||||||
// 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null
|
|
||||||
const newElements = (isCatchError && typeof clazz.getDerivedStateFromError !== 'function')
|
|
||||||
? null
|
|
||||||
: inst.render();
|
|
||||||
|
|
||||||
processing.child = createVNodeChildren(processing, newElements);
|
|
||||||
return processing.child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取当前节点的context
|
|
||||||
export function getCurrentContext(clazz, processing: VNode) {
|
|
||||||
const context = clazz.contextType;
|
|
||||||
return typeof context === 'object' && context !== null
|
|
||||||
? getNewContext(processing, context)
|
|
||||||
: getOldContext(processing, clazz, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 根据isUpdateComponent,执行不同的生命周期
|
|
||||||
function callUpdateLifeCycle(processing: VNode, nextProps: object, clazz) {
|
|
||||||
const inst = processing.realNode;
|
|
||||||
const newContext = getCurrentContext(clazz, processing);
|
|
||||||
if (processing.isCreated) {
|
|
||||||
callComponentWillMount(processing, inst);
|
|
||||||
} else {
|
|
||||||
callComponentWillUpdate(inst, nextProps, processing.state, newContext);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boolean) {
|
// 用于未完成的类组件
|
||||||
if (processing.isCreated) {
|
export function getIncompleteClassComponent(clazz, processing: VNode, nextProps: object): VNode | null {
|
||||||
markComponentDidMount(processing);
|
mountInstance(clazz, processing, nextProps);
|
||||||
} else if (processing.state !== processing.oldState || shouldUpdate) {
|
return createChildren(clazz, processing);
|
||||||
markComponentDidUpdate(processing);
|
|
||||||
markGetSnapshotBeforeUpdate(processing);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,14 +7,8 @@ import {FlagUtils} from '../vnode/VNodeFlags';
|
||||||
import {exeFunctionHook} from '../hooks/HookMain';
|
import {exeFunctionHook} from '../hooks/HookMain';
|
||||||
import {createVNodeChildren} from './BaseComponent';
|
import {createVNodeChildren} from './BaseComponent';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
|
||||||
return captureIndeterminateComponent(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender() {}
|
|
||||||
|
|
||||||
function captureIndeterminateComponent(
|
function captureIndeterminateComponent(
|
||||||
processing: VNode | null,
|
processing: VNode,
|
||||||
): VNode | null {
|
): VNode | null {
|
||||||
const funcComp = processing.type;
|
const funcComp = processing.type;
|
||||||
|
|
||||||
|
@ -34,3 +28,9 @@ function captureIndeterminateComponent(
|
||||||
processing.child = createVNodeChildren(processing, newElements);
|
processing.child = createVNodeChildren(processing, newElements);
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
|
return captureIndeterminateComponent(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bubbleRender() {}
|
||||||
|
|
|
@ -3,12 +3,6 @@ import type {VNode, ContextType} from '../Types';
|
||||||
import {resetDepContexts, getNewContext} from '../components/context/Context';
|
import {resetDepContexts, getNewContext} from '../components/context/Context';
|
||||||
import {createVNodeChildren} from './BaseComponent';
|
import {createVNodeChildren} from './BaseComponent';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
|
||||||
return captureContextConsumer(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender() {}
|
|
||||||
|
|
||||||
function captureContextConsumer(processing: VNode) {
|
function captureContextConsumer(processing: VNode) {
|
||||||
const context: ContextType<any> = processing.type;
|
const context: ContextType<any> = processing.type;
|
||||||
const props = processing.props;
|
const props = processing.props;
|
||||||
|
@ -21,3 +15,10 @@ function captureContextConsumer(processing: VNode) {
|
||||||
processing.child = createVNodeChildren(processing, newChildren);
|
processing.child = createVNodeChildren(processing, newChildren);
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
|
return captureContextConsumer(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bubbleRender() {}
|
||||||
|
|
||||||
|
|
|
@ -14,46 +14,6 @@ import {launchUpdateFromVNode} from '../TreeBuilder';
|
||||||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||||
import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate';
|
import {setParentsChildShouldUpdate} from '../vnode/VNodeShouldUpdate';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
|
||||||
return captureContextProvider(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
|
||||||
resetContextCtx(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function captureContextProvider(processing: VNode): VNode | null {
|
|
||||||
const providerType: ProviderType<any> = processing.type;
|
|
||||||
const contextType: ContextType<any> = providerType._context;
|
|
||||||
|
|
||||||
const newProps = processing.props;
|
|
||||||
const oldProps = !processing.isCreated ? processing.oldProps : null;
|
|
||||||
|
|
||||||
// 获取provider设置的context,即provider组件设置的value
|
|
||||||
const newCtx = newProps.value;
|
|
||||||
|
|
||||||
// 更新processing的context值为newProps.value
|
|
||||||
setContextCtx(processing, newCtx);
|
|
||||||
|
|
||||||
if (oldProps !== null) {
|
|
||||||
const oldCtx = oldProps.value;
|
|
||||||
const isSameContext = isSame(oldCtx, newCtx);
|
|
||||||
if (isSameContext) {
|
|
||||||
// context没有改变,复用
|
|
||||||
if (oldProps.children === newProps.children && !getContextChangeCtx()) {
|
|
||||||
return onlyUpdateChildVNodes(processing);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// context更改,更新所有依赖的组件
|
|
||||||
handleContextChange(processing, contextType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const newElements = newProps.children;
|
|
||||||
processing.child = createVNodeChildren(processing, newElements);
|
|
||||||
return processing.child;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从依赖中找到匹配context的VNode
|
// 从依赖中找到匹配context的VNode
|
||||||
function matchDependencies(depContexts, context, vNode): boolean {
|
function matchDependencies(depContexts, context, vNode): boolean {
|
||||||
for (let i = 0; i < depContexts.length; i++) {
|
for (let i = 0; i < depContexts.length; i++) {
|
||||||
|
@ -88,18 +48,59 @@ function handleContextChange(processing: VNode, context: ContextType<any>): void
|
||||||
let isMatch = false;
|
let isMatch = false;
|
||||||
|
|
||||||
// 从vNode开始遍历
|
// 从vNode开始遍历
|
||||||
travelVNodeTree(vNode, (node) => {
|
travelVNodeTree(vNode, node => {
|
||||||
const depContexts = node.depContexts;
|
const depContexts = node.depContexts;
|
||||||
if (depContexts.length) {
|
if (depContexts.length) {
|
||||||
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
|
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
|
||||||
}
|
}
|
||||||
}, (node) => {
|
}, node =>
|
||||||
// 如果这是匹配的provider,则不要更深入地扫描
|
// 如果这是匹配的provider,则不要更深入地扫描
|
||||||
return node.tag === ContextProvider && node.type === processing.type;
|
node.tag === ContextProvider && node.type === processing.type
|
||||||
}, processing);
|
, processing);
|
||||||
|
|
||||||
// 找到了依赖context的子节点,触发一次更新
|
// 找到了依赖context的子节点,触发一次更新
|
||||||
if (isMatch) {
|
if (isMatch) {
|
||||||
launchUpdateFromVNode(processing);
|
launchUpdateFromVNode(processing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function captureContextProvider(processing: VNode): VNode | null {
|
||||||
|
const providerType: ProviderType<any> = processing.type;
|
||||||
|
const contextType: ContextType<any> = providerType._context;
|
||||||
|
|
||||||
|
const newProps = processing.props;
|
||||||
|
const oldProps = !processing.isCreated ? processing.oldProps : null;
|
||||||
|
|
||||||
|
// 获取provider设置的context,即provider组件设置的value
|
||||||
|
const newCtx = newProps.value;
|
||||||
|
|
||||||
|
// 更新processing的context值为newProps.value
|
||||||
|
setContextCtx(processing, newCtx);
|
||||||
|
|
||||||
|
if (oldProps !== null) {
|
||||||
|
const oldCtx = oldProps.value;
|
||||||
|
const isSameContext = isSame(oldCtx, newCtx);
|
||||||
|
if (isSameContext) {
|
||||||
|
// context没有改变,复用
|
||||||
|
if (oldProps.children === newProps.children && !getContextChangeCtx()) {
|
||||||
|
return onlyUpdateChildVNodes(processing);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// context更改,更新所有依赖的组件
|
||||||
|
handleContextChange(processing, contextType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const newElements = newProps.children;
|
||||||
|
processing.child = createVNodeChildren(processing, newElements);
|
||||||
|
return processing.child;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
|
return captureContextProvider(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function bubbleRender(processing: VNode) {
|
||||||
|
resetContextCtx(processing);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,55 @@ import {createVNodeChildren, markRef} from './BaseComponent';
|
||||||
import {DomComponent, DomPortal, DomText} from '../vnode/VNodeTags';
|
import {DomComponent, DomPortal, DomText} from '../vnode/VNodeTags';
|
||||||
import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils';
|
import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
function updateDom(
|
||||||
return captureDomComponent(processing);
|
processing: VNode,
|
||||||
|
type: any,
|
||||||
|
newProps: Props,
|
||||||
|
) {
|
||||||
|
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
||||||
|
const oldProps = processing.oldProps;
|
||||||
|
if (oldProps === newProps) {
|
||||||
|
// 如果props没有发生变化,即使它的children发生了变化,我们也不会改变它
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const dom: Element = processing.realNode;
|
||||||
|
|
||||||
|
const changeList = getPropChangeList(
|
||||||
|
dom,
|
||||||
|
type,
|
||||||
|
oldProps,
|
||||||
|
newProps,
|
||||||
|
);
|
||||||
|
processing.changeList = changeList;
|
||||||
|
|
||||||
|
// 输入类型的直接标记更新
|
||||||
|
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
||||||
|
FlagUtils.markUpdate(processing);
|
||||||
|
} else {
|
||||||
|
// 其它的类型,数据有变化才标记更新
|
||||||
|
if (changeList.length) {
|
||||||
|
FlagUtils.markUpdate(processing);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 把dom类型的子节点append到parent dom中
|
||||||
|
function appendAllChildren(parent: Element, processing: VNode) {
|
||||||
|
const vNode = processing.child;
|
||||||
|
if (vNode === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 向下递归它的子节点,查找所有终端节点。
|
||||||
|
travelVNodeTree(vNode, node => {
|
||||||
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
|
appendChildElement(parent, node.realNode);
|
||||||
|
}
|
||||||
|
}, node =>
|
||||||
|
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||||
|
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
|
||||||
|
, processing);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
|
@ -86,53 +133,6 @@ function captureDomComponent(processing: VNode): VNode | null {
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 把dom类型的子节点append到parent dom中
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
function appendAllChildren(parent: Element, processing: VNode) {
|
return captureDomComponent(processing);
|
||||||
const vNode = processing.child;
|
|
||||||
if (vNode === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 向下递归它的子节点,查找所有终端节点。
|
|
||||||
travelVNodeTree(vNode, (node) => {
|
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
|
||||||
appendChildElement(parent, node.realNode);
|
|
||||||
}
|
|
||||||
}, (node) => {
|
|
||||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
|
||||||
return node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal;
|
|
||||||
}, processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
function updateDom(
|
|
||||||
processing: VNode,
|
|
||||||
type: any,
|
|
||||||
newProps: Props,
|
|
||||||
) {
|
|
||||||
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
|
||||||
const oldProps = processing.oldProps;
|
|
||||||
if (oldProps === newProps) {
|
|
||||||
// 如果props没有发生变化,即使它的children发生了变化,我们也不会改变它
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const dom: Element = processing.realNode;
|
|
||||||
|
|
||||||
const changeList = getPropChangeList(
|
|
||||||
dom,
|
|
||||||
type,
|
|
||||||
oldProps,
|
|
||||||
newProps,
|
|
||||||
);
|
|
||||||
processing.changeList = changeList;
|
|
||||||
|
|
||||||
// 输入类型的直接标记更新
|
|
||||||
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
|
||||||
FlagUtils.markUpdate(processing);
|
|
||||||
} else {
|
|
||||||
// 其它的类型,数据有变化才标记更新
|
|
||||||
if (changeList.length) {
|
|
||||||
FlagUtils.markUpdate(processing);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,6 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||||
import { createVNodeChildren } from './BaseComponent';
|
import { createVNodeChildren } from './BaseComponent';
|
||||||
import { prePortal } from '../../dom/DOMOperator';
|
import { prePortal } from '../../dom/DOMOperator';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
|
||||||
return capturePortalComponent(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
resetNamespaceCtx(processing);
|
resetNamespaceCtx(processing);
|
||||||
|
|
||||||
|
@ -27,3 +23,7 @@ function capturePortalComponent(processing: VNode) {
|
||||||
}
|
}
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
|
return capturePortalComponent(processing);
|
||||||
|
}
|
||||||
|
|
|
@ -13,23 +13,40 @@ import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||||
// 在useState, useReducer的时候,会触发state变化
|
// 在useState, useReducer的时候,会触发state变化
|
||||||
let stateChange = false;
|
let stateChange = false;
|
||||||
|
|
||||||
export function captureRender(processing: VNode, shouldUpdate?: boolean): VNode | null {
|
export function bubbleRender() {}
|
||||||
const Component = processing.type;
|
|
||||||
const unresolvedProps = processing.props;
|
|
||||||
const resolvedProps =
|
|
||||||
processing.isLazyComponent
|
|
||||||
? mergeDefaultProps(Component, unresolvedProps)
|
|
||||||
: unresolvedProps;
|
|
||||||
|
|
||||||
return captureFunctionComponent(
|
// 判断children是否可以复用
|
||||||
processing,
|
function checkIfCanReuseChildren(processing: VNode, shouldUpdate?: boolean) {
|
||||||
Component,
|
let isCanReuse = true;
|
||||||
resolvedProps,
|
|
||||||
shouldUpdate
|
if (!processing.isCreated) {
|
||||||
);
|
const oldProps = processing.oldProps;
|
||||||
|
const newProps = processing.props;
|
||||||
|
|
||||||
|
// 如果props或者context改变了
|
||||||
|
if (oldProps !== newProps || getContextChangeCtx() || processing.isDepContextChange) {
|
||||||
|
isCanReuse = false;
|
||||||
|
} else {
|
||||||
|
if (shouldUpdate && processing.suspenseChildThrow) {
|
||||||
|
// 使用完后恢复
|
||||||
|
processing.suspenseChildThrow = false;
|
||||||
|
isCanReuse = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isCanReuse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return isCanReuse;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender() {}
|
export function setStateChange(isUpdate) {
|
||||||
|
stateChange = isUpdate;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function isStateChange() {
|
||||||
|
return stateChange;
|
||||||
|
}
|
||||||
|
|
||||||
export function captureFunctionComponent(
|
export function captureFunctionComponent(
|
||||||
processing: VNode,
|
processing: VNode,
|
||||||
|
@ -66,35 +83,19 @@ export function captureFunctionComponent(
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 判断children是否可以复用
|
export function captureRender(processing: VNode, shouldUpdate?: boolean): VNode | null {
|
||||||
function checkIfCanReuseChildren(processing: VNode, shouldUpdate?: boolean) {
|
const Component = processing.type;
|
||||||
let isCanReuse = true;
|
const unresolvedProps = processing.props;
|
||||||
|
const resolvedProps =
|
||||||
|
processing.isLazyComponent
|
||||||
|
? mergeDefaultProps(Component, unresolvedProps)
|
||||||
|
: unresolvedProps;
|
||||||
|
|
||||||
if (!processing.isCreated) {
|
return captureFunctionComponent(
|
||||||
const oldProps = processing.oldProps;
|
processing,
|
||||||
const newProps = processing.props;
|
Component,
|
||||||
|
resolvedProps,
|
||||||
// 如果props或者context改变了
|
shouldUpdate
|
||||||
if (oldProps !== newProps || getContextChangeCtx() || processing.isDepContextChange) {
|
);
|
||||||
isCanReuse = false;
|
|
||||||
} else {
|
|
||||||
if (shouldUpdate && processing.suspenseChildThrow) {
|
|
||||||
// 使用完后恢复
|
|
||||||
processing.suspenseChildThrow = false;
|
|
||||||
isCanReuse = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
isCanReuse = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return isCanReuse;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setStateChange(isUpdate) {
|
|
||||||
stateChange = isUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isStateChange() {
|
|
||||||
return stateChange;
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,23 @@
|
||||||
import type {VNode} from '../Types';
|
import type { VNode } from '../Types';
|
||||||
|
|
||||||
import {FlagUtils} from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import {getLazyVNodeTag} from '../vnode/VNodeCreator';
|
import { getLazyVNodeTag } from '../vnode/VNodeCreator';
|
||||||
import {
|
import {
|
||||||
ClassComponent,
|
ClassComponent,
|
||||||
ForwardRef,
|
ForwardRef,
|
||||||
FunctionComponent,
|
FunctionComponent,
|
||||||
MemoComponent,
|
MemoComponent,
|
||||||
} from '../vnode/VNodeTags';
|
} from '../vnode/VNodeTags';
|
||||||
import {throwIfTrue} from '../utils/throwIfTrue';
|
import { throwIfTrue } from '../utils/throwIfTrue';
|
||||||
import {captureFunctionComponent} from './FunctionComponent';
|
import { captureFunctionComponent } from './FunctionComponent';
|
||||||
import {captureClassComponent} from './ClassComponent';
|
import { captureClassComponent } from './ClassComponent';
|
||||||
import {captureMemoComponent} from './MemoComponent';
|
import { captureMemoComponent } from './MemoComponent';
|
||||||
|
|
||||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||||
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender() {}
|
export function bubbleRender() { }
|
||||||
|
|
||||||
const LazyRendererMap = {
|
const LazyRendererMap = {
|
||||||
[FunctionComponent]: captureFunctionComponent,
|
[FunctionComponent]: captureFunctionComponent,
|
||||||
|
@ -64,12 +64,13 @@ function captureLazyComponent(
|
||||||
Component,
|
Component,
|
||||||
'',
|
'',
|
||||||
);
|
);
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mergeDefaultProps(Component: any, props: object): object {
|
export function mergeDefaultProps(Component: any, props: object): object {
|
||||||
if (Component && Component.defaultProps) {
|
if (Component && Component.defaultProps) {
|
||||||
const clonedProps = {...props};
|
const clonedProps = { ...props };
|
||||||
const defaultProps = Component.defaultProps;
|
const defaultProps = Component.defaultProps;
|
||||||
Object.keys(defaultProps).forEach(key => {
|
Object.keys(defaultProps).forEach(key => {
|
||||||
if (clonedProps[key] === undefined) {
|
if (clonedProps[key] === undefined) {
|
||||||
|
|
|
@ -7,7 +7,7 @@ import {
|
||||||
TYPE_FRAGMENT,
|
TYPE_FRAGMENT,
|
||||||
TYPE_PROFILER,
|
TYPE_PROFILER,
|
||||||
TYPE_STRICT_MODE,
|
TYPE_STRICT_MODE,
|
||||||
} from '../utils/elementType';
|
} from '../../external/JSXElementType';
|
||||||
import {Fragment} from '../vnode/VNodeTags';
|
import {Fragment} from '../vnode/VNodeTags';
|
||||||
|
|
||||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||||
|
|
|
@ -70,8 +70,9 @@ function callBeforeSubmitLifeCycles(
|
||||||
case TreeRoot: {
|
case TreeRoot: {
|
||||||
const root = vNode.realNode;
|
const root = vNode.realNode;
|
||||||
clearContainer(root.outerDom);
|
clearContainer(root.outerDom);
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -136,8 +137,9 @@ function callAfterSubmitLifeCycles(
|
||||||
vNode.realNode.focus();
|
vNode.realNode.focus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No Default
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,13 +159,19 @@ function hideOrUnhideAllChildren(vNode, isHidden) {
|
||||||
|
|
||||||
function attachRef(vNode: VNode) {
|
function attachRef(vNode: VNode) {
|
||||||
const ref = vNode.ref;
|
const ref = vNode.ref;
|
||||||
|
|
||||||
if (ref !== null) {
|
if (ref !== null) {
|
||||||
const instance = vNode.realNode;
|
const instance = vNode.realNode;
|
||||||
|
|
||||||
if (typeof ref === 'function') {
|
let refType = typeof ref;
|
||||||
|
if (refType === 'function') {
|
||||||
ref(instance);
|
ref(instance);
|
||||||
} else {
|
} else if (refType === 'object') {
|
||||||
(<RefType>ref).current = instance;
|
(<RefType>ref).current = instance;
|
||||||
|
} else {
|
||||||
|
if (vNode.belongClassVNode && vNode.belongClassVNode.realNode) {
|
||||||
|
vNode.belongClassVNode.realNode.refs[String(ref)] = instance;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -172,25 +180,26 @@ function detachRef(vNode: VNode, isOldRef?: boolean) {
|
||||||
let ref = (isOldRef ? vNode.oldRef : vNode.ref);
|
let ref = (isOldRef ? vNode.oldRef : vNode.ref);
|
||||||
|
|
||||||
if (ref !== null) {
|
if (ref !== null) {
|
||||||
if (typeof ref === 'function') {
|
let refType = typeof ref;
|
||||||
|
|
||||||
|
if (refType === 'function') {
|
||||||
try {
|
try {
|
||||||
ref(null);
|
ref(null);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
handleSubmitError(vNode, error);
|
handleSubmitError(vNode, error);
|
||||||
}
|
}
|
||||||
} else {
|
} else if (refType === 'object') {
|
||||||
(<RefType>ref).current = null;
|
(<RefType>ref).current = null;
|
||||||
|
} else {
|
||||||
|
if (vNode.belongClassVNode && vNode.belongClassVNode.realNode) {
|
||||||
|
vNode.belongClassVNode.realNode.refs[String(ref)] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 卸载一个vNode,不会递归
|
// 卸载一个vNode,不会递归
|
||||||
function unmountVNode(vNode: VNode): void {
|
function unmountVNode(vNode: VNode): void {
|
||||||
// TODO 暂时用于规避error处理逻辑,后续删除
|
|
||||||
if (vNode.flags.Addition) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (vNode.tag) {
|
switch (vNode.tag) {
|
||||||
case FunctionComponent:
|
case FunctionComponent:
|
||||||
case ForwardRef:
|
case ForwardRef:
|
||||||
|
|
|
@ -11,7 +11,7 @@ import {
|
||||||
callBeforeSubmitLifeCycles, submitDeletion, submitAddition,
|
callBeforeSubmitLifeCycles, submitDeletion, submitAddition,
|
||||||
submitResetTextContent, submitUpdate, detachRef,
|
submitResetTextContent, submitUpdate, detachRef,
|
||||||
} from './LifeCycleHandler';
|
} from './LifeCycleHandler';
|
||||||
import {tryRenderRoot, setProcessing, getStartVNode} from '../TreeBuilder';
|
import {tryRenderRoot, setProcessing} from '../TreeBuilder';
|
||||||
import {
|
import {
|
||||||
BySync,
|
BySync,
|
||||||
InRender,
|
InRender,
|
||||||
|
@ -24,6 +24,7 @@ import {
|
||||||
isSchedulingEffects,
|
isSchedulingEffects,
|
||||||
setSchedulingEffects, setHookEffectRoot,
|
setSchedulingEffects, setHookEffectRoot,
|
||||||
} from './HookEffectHandler';
|
} from './HookEffectHandler';
|
||||||
|
import {getStartVNode} from '../GlobalVar';
|
||||||
|
|
||||||
let rootThrowError = null;
|
let rootThrowError = null;
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
import type {VNode} from '../Types';
|
|
||||||
|
|
||||||
// 当前所有者是应拥有当前正在构建的任何组件的组件。
|
|
||||||
const ProcessingVNode: { val: VNode | null } = {
|
|
||||||
val: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ProcessingVNode;
|
|
|
@ -26,7 +26,7 @@ export class VNode {
|
||||||
suspensePromises: any = null; // suspense组件的promise列表
|
suspensePromises: any = null; // suspense组件的promise列表
|
||||||
changeList: any = null; // DOM的变更列表
|
changeList: any = null; // DOM的变更列表
|
||||||
effectList: any[] = []; // useEffect 的更新数组
|
effectList: any[] = []; // useEffect 的更新数组
|
||||||
updates: any[] = null; // TreeRoot和ClassComponent使用的更新数组
|
updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组
|
||||||
stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
|
stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
|
||||||
isForceUpdate: boolean = false; // 是否使用强制更新
|
isForceUpdate: boolean = false; // 是否使用强制更新
|
||||||
|
|
||||||
|
@ -76,6 +76,8 @@ export class VNode {
|
||||||
path: Array<number> = []; // 保存从根到本节点的路径
|
path: Array<number> = []; // 保存从根到本节点的路径
|
||||||
toUpdateNodes: Set<VNode> | null = null; // 保存要更新的节点
|
toUpdateNodes: Set<VNode> | null = null; // 保存要更新的节点
|
||||||
|
|
||||||
|
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
||||||
|
|
||||||
constructor(tag: VNodeTag, props: any, key: null | string, outerDom) {
|
constructor(tag: VNodeTag, props: any, key: null | string, outerDom) {
|
||||||
this.tag = tag; // 对应组件的类型,比如ClassComponent等
|
this.tag = tag; // 对应组件的类型,比如ClassComponent等
|
||||||
this.key = key;
|
this.key = key;
|
||||||
|
|
|
@ -24,9 +24,9 @@ import {
|
||||||
TYPE_MEMO, TYPE_PROFILER,
|
TYPE_MEMO, TYPE_PROFILER,
|
||||||
TYPE_PROVIDER, TYPE_STRICT_MODE,
|
TYPE_PROVIDER, TYPE_STRICT_MODE,
|
||||||
TYPE_SUSPENSE,
|
TYPE_SUSPENSE,
|
||||||
} from '../utils/elementType';
|
} from '../../external/JSXElementType';
|
||||||
import { VNode } from './VNode';
|
import { VNode } from './VNode';
|
||||||
import {HorizonElement} from '../Types';
|
import {JSXElement} from '../Types';
|
||||||
|
|
||||||
const typeLazyMap = {
|
const typeLazyMap = {
|
||||||
[TYPE_FORWARD_REF]: ForwardRef,
|
[TYPE_FORWARD_REF]: ForwardRef,
|
||||||
|
@ -156,7 +156,7 @@ export function updateVNodePath(vNode: VNode) {
|
||||||
vNode.path = [...vNode.parent.path, vNode.cIndex];
|
vNode.path = [...vNode.parent.path, vNode.cIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createVNodeFromElement(element: HorizonElement): VNode {
|
export function createVNodeFromElement(element: JSXElement): VNode {
|
||||||
const type = element.type;
|
const type = element.type;
|
||||||
const key = element.key;
|
const key = element.key;
|
||||||
const props = element.props;
|
const props = element.props;
|
||||||
|
|
|
@ -19,7 +19,7 @@ export const ShouldCapture = 'ShouldCapture';
|
||||||
// For suspense
|
// For suspense
|
||||||
export const ForceUpdate = 'ForceUpdate';
|
export const ForceUpdate = 'ForceUpdate';
|
||||||
|
|
||||||
const flagArr = [Addition, Update, Deletion, ResetText, Callback, DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate];
|
const FlagArr = [Addition, Update, Deletion, ResetText, Callback, DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate];
|
||||||
|
|
||||||
const LifecycleEffectArr = [Update, Callback, Ref, Snapshot];
|
const LifecycleEffectArr = [Update, Callback, Ref, Snapshot];
|
||||||
|
|
||||||
|
@ -38,9 +38,10 @@ export class FlagUtils {
|
||||||
}
|
}
|
||||||
static hasAnyFlag(node: VNode) { // 有标志位
|
static hasAnyFlag(node: VNode) { // 有标志位
|
||||||
let keyFlag = false;
|
let keyFlag = false;
|
||||||
flagArr.forEach(key => {
|
FlagArr.forEach(key => {
|
||||||
if (node.flags[key]) {
|
if (node.flags[key]) {
|
||||||
keyFlag = true;
|
keyFlag = true;
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return keyFlag;
|
return keyFlag;
|
||||||
|
|
|
@ -13,7 +13,7 @@ export function getSiblingVNode(node) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) {
|
export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) {
|
||||||
let node = beginVNode;
|
let node: VNode | null = beginVNode;
|
||||||
|
|
||||||
while (node !== null) {
|
while (node !== null) {
|
||||||
if (isFinish && isFinish(node)) {
|
if (isFinish && isFinish(node)) {
|
||||||
|
@ -77,10 +77,6 @@ export function travelVNodeTree(
|
||||||
|
|
||||||
// 置空vNode
|
// 置空vNode
|
||||||
export function clearVNode(vNode: VNode) {
|
export function clearVNode(vNode: VNode) {
|
||||||
clearOneVNode(vNode);
|
|
||||||
}
|
|
||||||
|
|
||||||
function clearOneVNode(vNode: VNode) {
|
|
||||||
vNode.child = null;
|
vNode.child = null;
|
||||||
vNode.next = null;
|
vNode.next = null;
|
||||||
vNode.depContexts = [];
|
vNode.depContexts = [];
|
||||||
|
@ -105,6 +101,8 @@ function clearOneVNode(vNode: VNode) {
|
||||||
|
|
||||||
vNode.path = [];
|
vNode.path = [];
|
||||||
vNode.toUpdateNodes = null;
|
vNode.toUpdateNodes = null;
|
||||||
|
|
||||||
|
vNode.belongClassVNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是dom类型的vNode
|
// 是dom类型的vNode
|
||||||
|
@ -144,6 +142,7 @@ export function findDomVNode(vNode: VNode): VNode | null {
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +223,7 @@ function isSameContainer(
|
||||||
}
|
}
|
||||||
// 注释类型的节点
|
// 注释类型的节点
|
||||||
if (isComment(container) && container.parentNode === targetContainer) {
|
if (isComment(container) && container.parentNode === targetContainer) {
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue