Match-id-89464fc71a41d2216aa19e6faa064878b774d431

This commit is contained in:
* 2022-02-17 20:22:25 +08:00 committed by *
commit 89ccca71ec
24 changed files with 423 additions and 374 deletions

View File

@ -14,13 +14,9 @@ import {
TreeRoot,
} from '../renderer/vnode/VNodeTags';
const prefix = '_horizon';
const internalKeys = {
VNode: `${prefix}VNode`,
props: `${prefix}Props`,
nonDelegatedEvents: `${prefix}NonDelegatedEvents`,
};
const INTERNAL_VNODE = '_horizon_VNode';
const INTERNAL_PROPS = '_horizon_Props';
const INTERNAL_NONDELEGATEEVENTS = '_horizon_NonDelegatedEvents';
// 通过 VNode 实例获取 DOM 节点
export function getDom(vNode: VNode): Element | Text | null {
@ -36,12 +32,12 @@ export function saveVNode(
vNode: VNode,
dom: Element | Text | Container,
): void {
dom[internalKeys.VNode] = vNode;
dom[INTERNAL_VNODE] = vNode;
}
// 用 DOM 节点,来找其对应的 VNode 实例
export function getVNode(dom: Node|Container): VNode | null {
const vNode = dom[internalKeys.VNode] || (dom as Container)._treeRoot;
const vNode = dom[INTERNAL_VNODE] || (dom as Container)._treeRoot;
if (vNode) {
const {tag} = vNode;
if (tag === DomComponent || tag === DomText || tag === TreeRoot) {
@ -53,7 +49,7 @@ export function getVNode(dom: Node|Container): VNode | null {
// 用 DOM 对象,来寻找其对应或者说是最近父级的 vNode
export function getNearestVNode(dom: Node): null | VNode {
let vNode = dom[internalKeys.VNode];
let vNode = dom[INTERNAL_VNODE];
if (vNode) { // 如果是已经被框架标记过的 DOM 节点,那么直接返回其 VNode 实例
return vNode;
}
@ -62,7 +58,7 @@ export function getNearestVNode(dom: Node): null | VNode {
let parentDom = dom.parentNode;
let nearVNode = null;
while (parentDom) {
vNode = parentDom[internalKeys.VNode];
vNode = parentDom[INTERNAL_VNODE];
if (vNode) {
nearVNode = vNode;
break;
@ -74,19 +70,19 @@ export function getNearestVNode(dom: Node): null | VNode {
// 获取 vNode 上的属性相关信息
export function getVNodeProps(dom: Element | Text): Props | null{
return dom[internalKeys.props] || null;
return dom[INTERNAL_PROPS] || null;
}
// 将 DOM 属性相关信息挂到 DOM 对象的特定属性上
export function updateVNodeProps(dom: Element | Text, props: Props): void {
dom[internalKeys.props] = props;
dom[INTERNAL_PROPS] = props;
}
export function getNonDelegatedListenerMap(dom: Element | Text): Map<string, EventListener> {
let eventsMap = dom[internalKeys.nonDelegatedEvents];
let eventsMap = dom[INTERNAL_NONDELEGATEEVENTS];
if (!eventsMap) {
eventsMap = new Map();
dom[internalKeys.nonDelegatedEvents] = eventsMap;
dom[INTERNAL_NONDELEGATEEVENTS] = eventsMap;
}
return eventsMap;
}

View File

@ -6,7 +6,7 @@ import {
createDom,
} from './utils/DomCreator';
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
import { shouldAutoFocus } from './utils/Common';
import { NSS } from './utils/DomCreator';
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
@ -165,7 +165,7 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
// 应用diff更新Properties.
// 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false.
if (type === 'input' && newProps.type === 'radio' && newProps.name != null && newProps.checked != null) {
updateCommonProp(element, 'checked', newProps.checked);
updateCommonProp(element, 'checked', newProps.checked, true);
}
const isNativeTag = isNativeElement(type, newProps);
updateDomProps(element, changeList, isNativeTag);

View File

@ -11,20 +11,18 @@ import { isEventProp, isNativeElement } from '../validators/ValidateProps';
function updateOneProp(dom, propName, isNativeTag, propVal?, isInit?: boolean) {
if (propName === 'style') {
setStyles(dom, propVal);
} else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html;
} else if (propName === 'children') { // 只处理纯文本子节点其他children在VNode树中处理
const type = typeof propVal;
if (type === 'string') {
dom.textContent = propVal;
} else if (type === 'number') {
dom.textContent = propVal + ''; // 这种数字转字符串的方式效率最高
}
} else if (isEventProp(propName)) {
// 事件监听属性处理
if (!allDelegatedHorizonEvents.has(propName)) {
listenNonDelegatedEvent(propName, dom, propVal);
}
} else if (propName === 'children') { // 只处理纯文本子节点其他children在VNode树中处理
const type = typeof propVal;
if (type === 'string' || type === 'number') {
dom.textContent = propVal;
}
} else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html;
} else {
if (!isInit || (isInit && propVal != null)) {
updateCommonProp(dom, propName, propVal, isNativeTag);
@ -40,10 +38,12 @@ export function setDomProps(
): void {
const isNativeTag = isNativeElement(tagName, props);
const keysOfProps = Object.keys(props);
for (let i = 0; i < keysOfProps.length; i++) {
const propName = keysOfProps[i];
const propVal = props[propName];
let propName;
let propVal;
const keyLength = keysOfProps.length;
for (let i = 0; i < keyLength; i++) {
propName = keysOfProps[i];
propVal = props[propName];
updateOneProp(dom, propName, isNativeTag, propVal, true);
}
@ -55,9 +55,12 @@ export function updateDomProps(
changeList: Array<any>,
isNativeTag: boolean,
): void {
for (let i = 0; i < changeList.length; i++) {
const { propName, propVal } = changeList[i];
const listLength = changeList.length;
let propName;
let propVal;
for (let i = 0; i < listLength; i++) {
propName = changeList[i].propName;
propVal = changeList[i].propVal;
updateOneProp(dom, propName, isNativeTag, propVal);
}
}
@ -73,19 +76,24 @@ export function compareProps(
const keysOfOldProps = Object.keys(oldProps);
const keysOfNewProps = Object.keys(newProps);
const oldPropsLength = keysOfOldProps.length;
let propName;
let oldStyle;
let styleProps;
let styleProp;
// 找到旧属性中需要删除的属性
for (let i = 0; i < keysOfOldProps.length; i++) {
const propName = keysOfOldProps[i];
for (let i = 0; i < oldPropsLength; i++) {
propName = keysOfOldProps[i];
// 新属性中包含该属性或者该属性为空值的属性不需要处理
if (keysOfNewProps.includes(propName) || oldProps[propName] == null) {
continue;
}
if (propName === 'style') {
const oldStyle = oldProps[propName];
const styleProps = Object.keys(oldStyle);
oldStyle = oldProps[propName];
styleProps = Object.keys(oldStyle);
for (let j = 0; j < styleProps.length; j++) {
const styleProp = styleProps[j];
styleProp = styleProps[j];
updatesForStyle[styleProp] = '';
}
} else if (
@ -110,11 +118,17 @@ export function compareProps(
}
}
let newPropValue;
let oldPropValue;
let oldStyleProps;
let newStyleProps;
let newHTML;
let oldHTML;
// 遍历新属性,获取新增和变更属性
for (let i = 0; i < keysOfNewProps.length; i++) {
const propName = keysOfNewProps[i];
const newPropValue = newProps[propName];
const oldPropValue = oldProps != null ? oldProps[propName] : null;
propName = keysOfNewProps[i];
newPropValue = newProps[propName];
oldPropValue = oldProps != null ? oldProps[propName] : null;
if (newPropValue === oldPropValue || (newPropValue == null && oldPropValue == null)) {
// 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理
@ -124,18 +138,18 @@ export function compareProps(
if (propName === 'style') {
if (oldPropValue) { // 之前 style 属性有设置非空值
// 原来有这个 style但现在没这个 style 了
const oldStyleProps = Object.keys(oldPropValue);
oldStyleProps = Object.keys(oldPropValue);
for (let j = 0; j < oldStyleProps.length; j++) {
const styleProp = oldStyleProps[j];
styleProp = oldStyleProps[j];
if (!newPropValue || !Object.prototype.hasOwnProperty.call(newPropValue, styleProp)) {
updatesForStyle[styleProp] = '';
}
}
// 现在有这个 style但是和原来不相等
const newStyleProps = newPropValue ? Object.keys(newPropValue) : [];
newStyleProps = newPropValue ? Object.keys(newPropValue) : [];
for (let j = 0; j < newStyleProps.length; j++) {
const styleProp = newStyleProps[j];
styleProp = newStyleProps[j];
if (oldPropValue[styleProp] !== newPropValue[styleProp]) {
updatesForStyle[styleProp] = newPropValue[styleProp];
}
@ -150,8 +164,8 @@ export function compareProps(
updatesForStyle = newPropValue;
}
} else if (propName === 'dangerouslySetInnerHTML') {
const newHTML = newPropValue ? newPropValue.__html : undefined;
const oldHTML = oldPropValue ? oldPropValue.__html : undefined;
newHTML = newPropValue ? newPropValue.__html : undefined;
oldHTML = oldPropValue ? oldPropValue.__html : undefined;
if (newHTML != null) {
if (oldHTML !== newHTML) {
toBeUpdatedProps.push({

View File

@ -29,7 +29,7 @@ function convertToLowerCase(str) {
* attrName class
* attrName DOM 使 property
*/
export function updateCommonProp(dom: Element, attrName: string, value: any, isNativeTag: boolean = true) {
export function updateCommonProp(dom: Element, attrName: string, value: any, isNativeTag: boolean) {
const propDetails = getPropDetails(attrName);
if (isInvalidValue(attrName, value, propDetails, isNativeTag)) {

View File

@ -5,13 +5,6 @@ export const NSS = {
svg: 'http://www.w3.org/2000/svg',
};
const div = document.createElement('div');
const span = document.createElement('span');
const tr = document.createElement('tr');
const td = document.createElement('td');
const a = document.createElement('a');
const p = document.createElement('p');
// 创建DOM元素
export function createDom(
tagName: string,
@ -23,18 +16,6 @@ export function createDom(
if (ns !== NSS.html) {
dom = document.createElementNS(ns, tagName);
} else if (tagName === 'div') {
dom = div.cloneNode(false);
} else if (tagName === 'span') {
dom = span.cloneNode(false);
} else if (tagName === 'tr') {
dom = tr.cloneNode(false);
} else if (tagName === 'td') {
dom = td.cloneNode(false);
} else if (tagName === 'a') {
dom = a.cloneNode(false);
} else if (tagName === 'p') {
dom = p.cloneNode(false);
} else {
dom = document.createElement(tagName);
}

View File

@ -37,7 +37,7 @@ export function updateInputValue(dom: HTMLInputElement, properties: IProperty) {
dom.value = String(value);
}
} else if (checked != null) {
updateCommonProp(dom, 'checked', checked);
updateCommonProp(dom, 'checked', checked, true);
}
}

View File

@ -29,17 +29,32 @@ let ctxOldContext: Object = {};
let ctxOldChange: Boolean = false;
let ctxOldPreviousContext: Object = {};
function setContext(vNode: VNode, contextName, value) {
if (vNode.contexts === null) {
vNode.contexts = {
[contextName]: value,
};
} else {
vNode.contexts[contextName] = value;
}
}
function getContext(vNode: VNode, contextName) {
if (vNode.contexts !== null) {
return vNode.contexts[contextName];
}
}
// capture阶段设置
function setNamespaceCtx(vNode: VNode, dom?: Container) {
const nextContext = getNSCtx(ctxNamespace, vNode.type, dom);
vNode.setContext(CTX_NAMESPACE, ctxNamespace);
setContext(vNode, CTX_NAMESPACE, ctxNamespace);
ctxNamespace = nextContext;
}
// bubble阶段恢复
function resetNamespaceCtx(vNode: VNode) {
ctxNamespace = vNode.getContext(CTX_NAMESPACE);
ctxNamespace = getContext(vNode, CTX_NAMESPACE);
}
function getNamespaceCtx(): string {
@ -49,14 +64,14 @@ function getNamespaceCtx(): string {
function setContextCtx<T>(providerVNode: VNode, nextValue: T) {
const context: ContextType<T> = providerVNode.type._context;
providerVNode.setContext(CTX_CONTEXT, context.value);
setContext(providerVNode, CTX_CONTEXT, context.value);
context.value = nextValue;
}
function resetContextCtx(providerVNode: VNode) {
const context: ContextType<any> = providerVNode.type._context;
context.value = providerVNode.getContext(CTX_CONTEXT);
context.value = getContext(providerVNode, CTX_CONTEXT);
}
// 在局部更新时恢复父节点的context
@ -74,11 +89,11 @@ function recoverParentsContextCtx(vNode: VNode) {
// ctxOldContext是 旧context提供者的context
function setVNodeOldContext(providerVNode: VNode, context: Object) {
providerVNode.setContext(CTX_OLD_CONTEXT, context);
setContext(providerVNode, CTX_OLD_CONTEXT, context);
}
function getVNodeOldContext(vNode: VNode) {
return vNode.getContext(CTX_OLD_CONTEXT);
return getContext(vNode, CTX_OLD_CONTEXT);
}
function setOldContextCtx(providerVNode: VNode, context: Object) {
@ -95,11 +110,11 @@ function resetOldContextCtx(vNode: VNode) {
}
function setVNodeOldPreviousContext(providerVNode: VNode, context: Object) {
providerVNode.setContext(CTX_OLD_PREVIOUS_CONTEXT, context);
setContext(providerVNode, CTX_OLD_PREVIOUS_CONTEXT, context);
}
function getVNodeOldPreviousContext(vNode: VNode) {
return vNode.getContext(CTX_OLD_PREVIOUS_CONTEXT);
return getContext(vNode, CTX_OLD_PREVIOUS_CONTEXT);
}
function setOldPreviousContextCtx(context: Object) {
@ -111,7 +126,7 @@ function getOldPreviousContextCtx() {
}
function setContextChangeCtx(providerVNode: VNode, didChange: boolean) {
providerVNode.setContext(CTX_OLD_CHANGE, didChange);
setContext(providerVNode, CTX_OLD_CHANGE, didChange);
ctxOldChange = didChange;
}
@ -120,7 +135,7 @@ function getContextChangeCtx() {
}
function resetContextChangeCtx(vNode: VNode) {
ctxOldChange = vNode.getContext(CTX_OLD_CHANGE);
ctxOldChange = getContext(vNode, CTX_OLD_CHANGE);
}
export {

View File

@ -6,7 +6,7 @@ import type {VNode} from './Types';
import type {Update} from './UpdateHandler';
import {ClassComponent, TreeRoot} from './vnode/VNodeTags';
import {FlagUtils, Interrupted} from './vnode/VNodeFlags';
import {FlagUtils, Interrupted, DidCapture, InitFlag} from './vnode/VNodeFlags';
import {newUpdate, UpdateState, pushUpdate} from './UpdateHandler';
import {launchUpdateFromVNode, tryRenderFromRoot} from './TreeBuilder';
import {setRootThrowError} from './submit/Submit';
@ -71,7 +71,7 @@ export function handleRenderThrowError(
// vNode抛出了异常标记Interrupted中断
FlagUtils.markInterrupted(sourceVNode);
// dirtyNodes 不再有效
sourceVNode.dirtyNodes = [];
sourceVNode.dirtyNodes = null;
// error是个promise
if (error !== null && typeof error === 'object' && typeof error.then === 'function') {
@ -99,7 +99,7 @@ export function handleRenderThrowError(
const ctor = vNode.type;
const instance = vNode.realNode;
if (
!vNode.flags.DidCapture &&
(vNode.flags & DidCapture) === InitFlag &&
(
typeof ctor.getDerivedStateFromError === 'function' ||
(instance !== null && typeof instance.componentDidCatch === 'function')

View File

@ -3,7 +3,7 @@ import type { VNode } from './Types';
import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue';
import { updateVNode } from './vnode/VNodeCreator';
import { TreeRoot } from './vnode/VNodeTags';
import { FlagUtils } from './vnode/VNodeFlags';
import { FlagUtils, InitFlag, Interrupted } from './vnode/VNodeFlags';
import { captureVNode } from './render/BaseComponent';
import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit';
import { runAsyncEffects } from './submit/HookEffectHandler';
@ -18,7 +18,7 @@ import {
setProcessingClassVNode,
setStartVNode
} from './GlobalVar';
import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils';
import { findDomParent } from './vnode/VNodeUtils';
import {
ByAsync,
BySync,
@ -57,10 +57,23 @@ function resetProcessingVariables(startUpdateVNode: VNode) {
// 收集有变化的节点在submit阶段继续处理
function collectDirtyNodes(vNode: VNode, parent: VNode): void {
// 将子树和此vNode的所有效果附加到父树的效果列表中子项的完成顺序会影响副作用顺序。
parent.dirtyNodes.push(...vNode.dirtyNodes);
const dirtyNodes = vNode.dirtyNodes;
if (dirtyNodes !== null && dirtyNodes.length) {
if (parent.dirtyNodes === null) {
parent.dirtyNodes = [...vNode.dirtyNodes];
} else {
parent.dirtyNodes.push(...vNode.dirtyNodes);
}
dirtyNodes.length = 0;
vNode.dirtyNodes = null;
}
if (FlagUtils.hasAnyFlag(vNode)) {
parent.dirtyNodes.push(vNode);
if (parent.dirtyNodes === null) {
parent.dirtyNodes = [vNode];
} else {
parent.dirtyNodes.push(vNode);
}
}
}
@ -73,13 +86,13 @@ function bubbleVNode(vNode: VNode): void {
do {
const parent = node.parent;
if (!node.flags.Interrupted) { // vNode没有抛出异常
if ((node.flags & Interrupted) === InitFlag) { // vNode没有抛出异常
componentRenders[node.tag].bubbleRender(node);
// 设置node的childShouldUpdate属性
updateChildShouldUpdate(node);
if (parent !== null && node !== getStartVNode() && !parent.flags.Interrupted) {
if (parent !== null && node !== getStartVNode() && (parent.flags & Interrupted) === InitFlag) {
collectDirtyNodes(node, parent);
}
}
@ -95,7 +108,7 @@ function bubbleVNode(vNode: VNode): void {
break;
}
const siblingVNode = getSiblingVNode(node);
const siblingVNode = node.next;
if (siblingVNode !== null) { // 有兄弟vNode
processing = siblingVNode;
return;

View File

@ -72,7 +72,11 @@ function calcState(
function collectCallbacks(vNode: VNode, update: Update) {
if (update.callback !== null) {
FlagUtils.markCallback(vNode);
vNode.stateCallbacks.push(update.callback);
if (vNode.stateCallbacks === null) {
vNode.stateCallbacks = [update.callback];
} else {
vNode.stateCallbacks.push(update.callback);
}
}
}

View File

@ -4,17 +4,19 @@ import {throwNotInFuncError} from '../../hooks/BaseHook';
// 重置依赖
export function resetDepContexts(vNode: VNode): void {
vNode.depContexts = [];
vNode.depContexts = null;
}
// 收集依赖
function collectDeps<T>(vNode: VNode, context: ContextType<T>) {
const depContexts = vNode.depContexts;
if (!depContexts.length) {
if (depContexts === null) {
vNode.depContexts = [context];
} else {
vNode.isDepContextChange = false;
}
if (!depContexts.includes(context)) {
depContexts.push(context);
if (!depContexts.includes(context)) {
depContexts.push(context);
}
}
}

View File

@ -9,10 +9,6 @@ export function isTextType(newChild: any) {
return typeof newChild === 'string' || typeof newChild === 'number';
}
export function isArrayType(newChild: any) {
return Array.isArray(newChild);
}
export function isIteratorType(newChild: any) {
return (typeof Symbol === 'function' && newChild[Symbol.iterator]) || newChild['@@iterator'];
}

View File

@ -7,11 +7,10 @@ import {
isSameType,
getIteratorFn,
isTextType,
isArrayType,
isIteratorType,
isObjectType,
} from './DiffTools';
import {getSiblingVNode, travelChildren} from '../vnode/VNodeUtils';
import { travelChildren } from '../vnode/VNodeUtils';
enum DiffCategory {
TEXT_NODE = 'TEXT_NODE',
@ -27,6 +26,10 @@ function isNoKeyFragment(child: any) {
// 清除单个节点
function deleteVNode(parentNode: VNode, delVNode: VNode): void {
FlagUtils.setDeletion(delVNode);
if (parentNode.dirtyNodes === null) {
parentNode.dirtyNodes = [delVNode];
return;
}
parentNode.dirtyNodes.push(delVNode);
}
@ -56,7 +59,7 @@ function checkCanReuseNode(oldNode: VNode | null, newChild: any): boolean {
}
if (isObjectType(newChild)) {
if (isArrayType(newChild) || isIteratorType(newChild)) {
if (Array.isArray(newChild) || isIteratorType(newChild)) {
return oldKey === null;
}
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
@ -75,7 +78,7 @@ function getNodeType(newChild: any): string | null {
return DiffCategory.TEXT_NODE;
}
if (isObjectType(newChild)) {
if (isArrayType(newChild) || isIteratorType(newChild)) {
if (Array.isArray(newChild) || isIteratorType(newChild)) {
return DiffCategory.ARR_NODE;
}
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
@ -196,7 +199,7 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
return nodeMap.get(newIdx) || null;
}
if (isObjectType(newChild)) {
if (isArrayType(newChild) || isIteratorType(newChild)) {
if (Array.isArray(newChild) || isIteratorType(newChild)) {
return nodeMap.get(newIdx) || null;
}
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
@ -212,11 +215,11 @@ function setCIndex(vNode: VNode, idx: number) {
}
// diff数组类型的节点核心算法
function diffArrayNodes(
function diffArrayNodesHandler(
parentNode: VNode,
firstChild: VNode | null,
newChildren: Array<any>,
isComparing: boolean = true
isComparing: boolean
): VNode | null {
let resultingFirstChild: VNode | null = null;
@ -238,6 +241,8 @@ function diffArrayNodes(
prevNewNode = newNode;
}
let canBeReuse;
let newNode;
// 1. 从左侧开始比对currentVNode和newChildren若不能复用则跳出循环
for (; oldNode !== null && leftIdx < newChildren.length; leftIdx++) {
if (oldNode.eIndex > leftIdx) {
@ -245,17 +250,17 @@ function diffArrayNodes(
nextOldNode = oldNode;
oldNode = null;
} else {
nextOldNode = getSiblingVNode(oldNode);
nextOldNode = oldNode.next;
}
const canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx]);
canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx]);
// 不能复用break
if (!canBeReuse) {
oldNode = oldNode ?? nextOldNode;
break;
}
const newNode = getNewNode(parentNode, newChildren[leftIdx], oldNode);
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNode);
// 没有生成新节点break
if (!newNode) {
oldNode = oldNode ?? nextOldNode;
@ -283,19 +288,20 @@ function diffArrayNodes(
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
// 2. 从右侧开始比对currentVNode和newChildren若不能复用则跳出循环
let rightOldNode;
for (; rightIdx > leftIdx; rightIdx--) {
const rightOldNode = rightRemainingOldChildren[rightOldIndex];
rightOldNode = rightRemainingOldChildren[rightOldIndex];
if (rightOldIndex < 0 || rightOldNode === null) {
break;
}
const canBeReuse = checkCanReuseNode(rightOldNode, newChildren[rightIdx - 1]);
canBeReuse = checkCanReuseNode(rightOldNode, newChildren[rightIdx - 1]);
// 不能复用break
if (!canBeReuse) {
break;
}
const newNode = getNewNode(parentNode, newChildren[rightIdx - 1], rightOldNode);
newNode = getNewNode(parentNode, newChildren[rightIdx - 1], rightOldNode);
// 没有生成新节点break
if (newNode === null) {
break;
@ -342,7 +348,7 @@ function diffArrayNodes(
// 4. 新节点还有一部分,但是老节点已经没有了
if (oldNode === null) {
for (; leftIdx < rightIdx; leftIdx++) {
const newNode = getNewNode(parentNode, newChildren[leftIdx], null);
newNode = getNewNode(parentNode, newChildren[leftIdx], null);
if (newNode !== null) {
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing);
@ -368,9 +374,11 @@ function diffArrayNodes(
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确通过记录preIndex找到正确值
const reuseNodes = []; // 记录复用的 VNode
let i = 0;
let oldNodeFromMap;
let last;
for (; leftIdx < rightIdx; leftIdx++) {
const oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
const newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
if (newNode !== null) {
if (isComparing && !newNode.isCreated) {
// 从Map删除后面不会deleteVNode
@ -380,7 +388,7 @@ function diffArrayNodes(
if (oldNodeFromMap !== null) {
let eIndex = newNode.eIndex;
eIndexes.push(eIndex);
const last: number | undefined = eIndexes[result[result.length - 1]];
last = eIndexes[result[result.length - 1]];
if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后
preIndex[i] = result[result.length - 1];
result.push(i);
@ -458,16 +466,6 @@ function setVNodesCIndex(startChild: VNode, startIdx: number) {
}
}
// 新节点是数组类型
function diffArrayNodesHandler(
parentNode: VNode,
firstChild: VNode | null,
newChildren: Array<any>,
isComparing: boolean = true
): VNode | null {
return diffArrayNodes(parentNode, firstChild, newChildren, isComparing);
}
// 新节点是迭代器类型
function diffIteratorNodesHandler(
parentNode: VNode,
@ -486,7 +484,7 @@ function diffIteratorNodesHandler(
result = iteratorObj.next();
}
return diffArrayNodes(parentNode, firstChild, childrenArray, isComparing);
return diffArrayNodesHandler(parentNode, firstChild, childrenArray, isComparing);
}
// 新节点是字符串类型
@ -548,13 +546,13 @@ function diffObjectNodeHandler(
// 可以复用
if (canReuseNode.tag === Fragment && newChild.type === TYPE_FRAGMENT) {
resultNode = updateVNode(canReuseNode, newChild.props.children);
startDelVNode = getSiblingVNode(canReuseNode);
startDelVNode = canReuseNode.next;
resultNode.next = null;
} else if (isSameType(canReuseNode, newChild)) {
resultNode = updateVNode(canReuseNode, newChild.props);
resultNode.ref = newChild.ref;
resultNode.belongClassVNode = newChild.belongClassVNode;
startDelVNode = getSiblingVNode(resultNode);
startDelVNode = resultNode.next;
resultNode.next = null;
}
}
@ -574,7 +572,7 @@ function diffObjectNodeHandler(
// 可以复用
if (canReuseNode.tag === DomPortal && canReuseNode.outerDom === newChild.outerDom) {
resultNode = updateVNode(canReuseNode, newChild.children || []);
startDelVNode = getSiblingVNode(canReuseNode);
startDelVNode = canReuseNode.next;
resultNode.next = null;
}
}
@ -625,7 +623,7 @@ export function createChildrenByDiff(
}
// 3. newChild是数组类型
if (isArrayType(newChild)) {
if (Array.isArray(newChild)) {
return diffArrayNodesHandler(parentNode, firstChild, newChild, isComparing);
}

View File

@ -66,9 +66,7 @@ export function captureVNode(processing: VNode): VNode | null {
// 创建孩子节点
export function createVNodeChildren(processing: VNode, nextChildren: any) {
const isComparing = !processing.isCreated;
return createChildrenByDiff(processing, processing.child, nextChildren, isComparing);
return createChildrenByDiff(processing, processing.child, nextChildren, !processing.isCreated);
}
export function markRef(processing: VNode) {

View File

@ -20,7 +20,7 @@ import {
markComponentDidUpdate,
markGetSnapshotBeforeUpdate,
} from './class/ClassLifeCycleProcessor';
import { FlagUtils } from '../vnode/VNodeFlags';
import { FlagUtils, DidCapture } from '../vnode/VNodeFlags';
import { createVNodeChildren, markRef } from './BaseComponent';
import {
createUpdateArray,
@ -73,7 +73,7 @@ function createChildren(clazz: any, processing: VNode) {
processing.state = processing.realNode.state;
const inst = processing.realNode;
const isCatchError = processing.flags.DidCapture;
const isCatchError = (processing.flags & DidCapture) === DidCapture;
// 按照已有规格如果捕获了错误却没有定义getDerivedStateFromError函数返回的child为null
const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function'
@ -122,7 +122,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
const newContext = getCurrentContext(clazz, processing);
// 子节点抛出异常时如果本class是个捕获异常的处理节点这时候oldProps是null所以需要使用props
let oldProps = processing.flags.DidCapture ? processing.props : processing.oldProps;
let oldProps = (processing.flags & DidCapture) === DidCapture ? processing.props : processing.oldProps;
if (processing.isLazyComponent) {
oldProps = mergeDefaultProps(processing.type, oldProps);
}
@ -161,7 +161,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
inst.props = nextProps;
}
// 如果捕获了 error必须更新
const isCatchError = processing.flags.DidCapture;
const isCatchError = (processing.flags & DidCapture) === DidCapture;
shouldUpdate = isCatchError || shouldUpdate;
// 更新ref

View File

@ -50,7 +50,7 @@ function handleContextChange(processing: VNode, context: ContextType<any>): void
// 从vNode开始遍历
travelVNodeTree(vNode, node => {
const depContexts = node.depContexts;
if (depContexts.length) {
if (depContexts && depContexts.length) {
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
}
}, node =>

View File

@ -1,5 +1,5 @@
import type {VNode} from '../Types';
import type {Props} from '../../dom/DOMOperator';
import type { VNode } from '../Types';
import type { Props } from '../../dom/DOMOperator';
import {
getNamespaceCtx,
@ -12,10 +12,10 @@ import {
initDomProps, getPropChangeList,
isTextChild,
} from '../../dom/DOMOperator';
import {FlagUtils} from '../vnode/VNodeFlags';
import {createVNodeChildren, markRef} from './BaseComponent';
import {DomComponent, DomPortal, DomText} from '../vnode/VNodeTags';
import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils';
import { FlagUtils } from '../vnode/VNodeFlags';
import { createVNodeChildren, markRef } from './BaseComponent';
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
import { travelVNodeTree } from '../vnode/VNodeUtils';
function updateDom(
processing: VNode,
@ -50,24 +50,6 @@ function updateDom(
}
}
// 把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) {
resetNamespaceCtx(processing);
@ -95,7 +77,19 @@ export function bubbleRender(processing: VNode) {
processing,
);
appendAllChildren(dom, processing);
// 把dom类型的子节点append到parent dom中
const vNode = processing.child;
if (vNode !== null) {
// 向下递归它的子节点,查找所有终端节点。
travelVNodeTree(vNode, node => {
if (node.tag === DomComponent || node.tag === DomText) {
appendChildElement(dom, node.realNode);
}
}, node =>
// 已经append到父节点或者是DomPortal都不需要处理child了
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
, processing);
}
processing.realNode = dom;

View File

@ -27,23 +27,24 @@ export function isSchedulingEffects() {
export function callUseEffects(vNode: VNode) {
const effectList: EffectList = vNode.effectList;
if (effectList !== null) {
effectList.forEach(effect => {
const {effectConstant} = effect;
if (
(effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect &&
(effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect
) {
hookEffects.push(effect);
hookRemoveEffects.push(effect);
effectList.forEach(effect => {
const {effectConstant} = effect;
if (
(effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect &&
(effectConstant & EffectConstant.DepsChange) !== EffectConstant.NoEffect
) {
hookEffects.push(effect);
hookRemoveEffects.push(effect);
// 异步调用
if (!isScheduling) {
isScheduling = true;
runAsync(runAsyncEffects);
// 异步调用
if (!isScheduling) {
isScheduling = true;
runAsync(runAsyncEffects);
}
}
}
});
});
}
}
export function runAsyncEffects() {
@ -85,23 +86,24 @@ export function runAsyncEffects() {
// 在销毁vNode的时候调用remove
export function callEffectRemove(vNode: VNode) {
const effectList: EffectList = vNode.effectList;
if (effectList !== null) {
effectList.forEach(effect => {
const {removeEffect, effectConstant} = effect;
effectList.forEach(effect => {
const {removeEffect, effectConstant} = effect;
if (removeEffect !== undefined) {
if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect就异步调用
hookRemoveEffects.push(effect);
if (removeEffect !== undefined) {
if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect就异步调用
hookRemoveEffects.push(effect);
if (!isScheduling) {
isScheduling = true;
runAsync(runAsyncEffects);
if (!isScheduling) {
isScheduling = true;
runAsync(runAsyncEffects);
}
} else { // 是useLayoutEffect直接执行
removeEffect();
}
} else { // 是useLayoutEffect直接执行
removeEffect();
}
}
});
});
}
}
// 同步执行UseLayoutEffect的remove
@ -109,26 +111,29 @@ export function callUseLayoutEffectRemove(vNode: VNode) {
const effectList: EffectList = vNode.effectList;
const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange;
effectList.forEach(effect => {
if ((effect.effectConstant & layoutLabel) === layoutLabel) {
const remove = effect.removeEffect;
effect.removeEffect = undefined;
if (typeof remove === 'function') {
remove();
if (effectList !== null) {
effectList.forEach(effect => {
if ((effect.effectConstant & layoutLabel) === layoutLabel) {
const remove = effect.removeEffect;
effect.removeEffect = undefined;
if (typeof remove === 'function') {
remove();
}
}
}
});
});
}
}
// 同步执行UseLayoutEffect
export function callUseLayoutEffectCreate(vNode: VNode) {
const effectList: EffectList = vNode.effectList;
const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange;
effectList.forEach(effect => {
if ((effect.effectConstant & layoutLabel) === layoutLabel) {
const create = effect.effect;
effect.removeEffect = create();
}
});
if (effectList !== null) {
const layoutLabel = EffectConstant.LayoutEffect | EffectConstant.DepsChange;
effectList.forEach(effect => {
if ((effect.effectConstant & layoutLabel) === layoutLabel) {
const create = effect.effect;
effect.removeEffect = create();
}
});
}
}

View File

@ -17,7 +17,7 @@ import {
SuspenseComponent,
MemoComponent,
} from '../vnode/VNodeTags';
import { FlagUtils, ResetText, Clear } from '../vnode/VNodeFlags';
import { FlagUtils, ResetText, Clear, Update } from '../vnode/VNodeFlags';
import { mergeDefaultProps } from '../render/LazyComponent';
import {
submitDomUpdate,
@ -72,13 +72,14 @@ function callBeforeSubmitLifeCycles(
// 调用vNode.stateCallbacks
function callStateCallback(vNode: VNode, obj: any): void {
const stateCallbacks = vNode.stateCallbacks;
vNode.stateCallbacks = [];
stateCallbacks.forEach(callback => {
if (typeof callback === 'function') {
callback.call(obj);
}
});
vNode.stateCallbacks = null;
if (stateCallbacks !== null) {
stateCallbacks.forEach(callback => {
if (typeof callback === 'function') {
callback.call(obj);
}
});
}
}
// 调用界面变化后的生命周期
@ -96,7 +97,7 @@ function callAfterSubmitLifeCycles(
}
case ClassComponent: {
const instance = vNode.realNode;
if (vNode.flags.Update) {
if ((vNode.flags & Update) === Update) {
if (vNode.isCreated) {
instance.componentDidMount();
} else {
@ -123,7 +124,7 @@ function callAfterSubmitLifeCycles(
return;
}
case DomComponent: {
if (vNode.isCreated && vNode.flags.Update) {
if (vNode.isCreated && (vNode.flags & Update) === Update) {
// button、input、select、textarea、如果有 autoFocus 属性需要focus
if (shouldAutoFocus(vNode.type, vNode.props)) {
vNode.realNode.focus();
@ -221,7 +222,7 @@ function unmountNestedVNodes(vNode: VNode): void {
function submitAddition(vNode: VNode): void {
const { parent, parentDom } = findDomParent(vNode);
if (parent.flags.ResetText) {
if ((vNode.flags & ResetText) === ResetText) {
// 在insert之前先reset
clearText(parentDom);
FlagUtils.removeFlag(parent, ResetText);

View File

@ -1,8 +1,6 @@
import type {VNode} from '../Types';
import {callRenderQueueImmediate} from '../taskExecutor/RenderQueue';
import {throwIfTrue} from '../utils/throwIfTrue';
import {FlagUtils, Addition as AdditionFlag} from '../vnode/VNodeFlags';
import {FlagUtils, Addition, Snapshot, ResetText, Ref, Update, Deletion, Clear, Callback} from '../vnode/VNodeFlags';
import {prepareForSubmit, resetAfterSubmit} from '../../dom/DOMOperator';
import {handleSubmitError} from '../ErrorHandler';
import {
@ -40,11 +38,15 @@ export function submitToRender(treeRoot) {
if (FlagUtils.hasAnyFlag(startVNode)) {
// 把自己加上
startVNode.dirtyNodes.push(startVNode);
if (startVNode.dirtyNodes === null) {
startVNode.dirtyNodes = [startVNode];
} else {
startVNode.dirtyNodes.push(startVNode);
}
}
const dirtyNodes = startVNode.dirtyNodes;
if (dirtyNodes.length) {
if (dirtyNodes !== null && dirtyNodes.length) {
const preMode = copyExecuteMode();
changeMode(InRender, true);
@ -60,7 +62,9 @@ export function submitToRender(treeRoot) {
// after submit阶段
afterSubmit(dirtyNodes);
setExecuteMode(preMode)
setExecuteMode(preMode);
dirtyNodes.length = 0;
startVNode.dirtyNodes = null;
}
if (isSchedulingEffects()) {
@ -85,7 +89,7 @@ export function submitToRender(treeRoot) {
function beforeSubmit(dirtyNodes: Array<VNode>) {
dirtyNodes.forEach(node => {
try {
if (node.flags.Snapshot) {
if ((node.flags & Snapshot) === Snapshot) {
callBeforeSubmitLifeCycles(node);
}
} catch (error) {
@ -97,35 +101,38 @@ function beforeSubmit(dirtyNodes: Array<VNode>) {
function submit(dirtyNodes: Array<VNode>) {
dirtyNodes.forEach(node => {
try {
if (node.flags.ResetText) {
if ((node.flags & ResetText) === ResetText) {
submitResetTextContent(node);
}
if (node.flags.Ref) {
if ((node.flags & Ref) === Ref) {
if (!node.isCreated) {
// 需要执行
detachRef(node, true);
}
}
const {Addition, Update, Deletion, Clear} = node.flags;
if (Addition && Update) {
const isAdd = (node.flags & Addition) === Addition;
const isUpdate = (node.flags & Update) === Update;
if (isAdd && isUpdate) {
// Addition
submitAddition(node);
FlagUtils.removeFlag(node, AdditionFlag);
FlagUtils.removeFlag(node, Addition);
// Update
submitUpdate(node);
} else {
if (Addition) {
const isDeletion = (node.flags & Deletion) === Deletion;
const isClear = (node.flags & Clear) === Clear;
if (isAdd) {
submitAddition(node);
FlagUtils.removeFlag(node, AdditionFlag);
} else if (Update) {
FlagUtils.removeFlag(node, Addition);
} else if (isUpdate) {
submitUpdate(node);
} else if (Deletion) {
} else if (isDeletion) {
submitDeletion(node);
}
if (Clear) {
if (isClear) {
submitClear(node);
}
}
@ -138,11 +145,11 @@ function submit(dirtyNodes: Array<VNode>) {
function afterSubmit(dirtyNodes: Array<VNode>) {
dirtyNodes.forEach(node => {
try {
if (node.flags.Update || node.flags.Callback) {
if ((node.flags & Update) === Update || (node.flags & Callback) === Callback) {
callAfterSubmitLifeCycles(node);
}
if (node.flags.Ref) {
if ((node.flags & Ref) === Ref) {
attachRef(node);
}
} catch (error) {

View File

@ -1,16 +1,18 @@
/**
* DOM结构体
*/
import {TreeRoot} from './VNodeTags';
import type {VNodeTag} from './VNodeTags';
import type {RefType, ContextType} from '../Types';
import type {Hook} from '../hooks/HookType';
import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, ContextConsumer, ForwardRef, SuspenseComponent, LazyComponent, ClsOrFunComponent, DomComponent, Fragment, ContextProvider, Profiler, MemoComponent, IncompleteClassComponent } from './VNodeTags';
import type { VNodeTag } from './VNodeTags';
import type { RefType, ContextType } from '../Types';
import type { Hook } from '../hooks/HookType';
import { InitFlag } from './VNodeFlags';
export class VNode {
tag: VNodeTag;
key: string | null; // 唯一标识符
props: any; // 传给组件的props的值类组件包含defaultPropsLazy组件不包含
type: any = null;
realNode: any = null; // 如果是类则存放实例如果是div这种则存放真实DOM
realNode: any; // 如果是类则存放实例如果是div这种则存放真实DOM
// 关系结构
parent: VNode | null = null; // 父节点
@ -20,62 +22,48 @@ export class VNode {
eIndex: number = 0; // HorizonElement在jsx中的位置例如jsx中的null不会生成vNode所以eIndex和cIndex不一致
ref: RefType | ((handle: any) => void) | null = null; // 包裹一个函数submit阶段使用比如将外部useRef生成的对象赋值到ref上
props: any; // 传给组件的props的值类组件包含defaultPropsLazy组件不包含
oldProps: any = null;
suspensePromises: any = null; // suspense组件的promise列表
changeList: any = null; // DOM的变更列表
effectList: any[] = []; // useEffect 的更新数组
updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组
stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
isForceUpdate: boolean = false; // 是否使用强制更新
suspensePromises: any; // suspense组件的promise列表
changeList: any; // DOM的变更列表
effectList: any[] | null; // useEffect 的更新数组
updates: any[] | null; // TreeRoot和ClassComponent使用的更新数组
stateCallbacks: any[] | null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
isForceUpdate: boolean; // 是否使用强制更新
state: any = null; // ClassComponent和TreeRoot的状态
hooks: Array<Hook<any, any>> = []; // 保存hook
state: any; // ClassComponent和TreeRoot的状态
hooks: Array<Hook<any, any>> | null; // 保存hook
suspenseChildStatus: string = ''; // Suspense的Children是否显示
depContexts: Array<ContextType<any>> = []; // FunctionComponent和ClassComponent对context的依赖列表
isDepContextChange: boolean = false; // context是否变更
dirtyNodes: Array<VNode> = []; // 需要改动的节点数组
depContexts: Array<ContextType<any>> | null; // FunctionComponent和ClassComponent对context的依赖列表
isDepContextChange: boolean; // context是否变更
dirtyNodes: Array<VNode> | null = null; // 需要改动的节点数组
shouldUpdate: boolean = false;
childShouldUpdate: boolean = false;
outerDom: any;
task: any;
// 使用这个变量来记录修改前的值,用于恢复。
contexts = {};
contexts: any;
// 因为LazyComponent会修改tag和type属性为了能识别增加一个属性
isLazyComponent: boolean = false;
isLazyComponent: boolean;
// 因为LazyComponent会修改type属性为了在diff中判断是否可以复用需要增加一个lazyType
lazyType: any = null;
flags: {
Addition?: boolean;
Update?: boolean;
Deletion?: boolean;
ResetText?: boolean;
Callback?: boolean;
DidCapture?: boolean;
Ref?: boolean;
Snapshot?: boolean;
Interrupted?: boolean;
ShouldCapture?: boolean;
ForceUpdate?: boolean;
Clear?: boolean;
} = {};
clearChild: VNode | null = null;
lazyType: any;
flags = InitFlag;
clearChild: VNode | null;
// one tree相关属性
isCreated: boolean = true;
oldHooks: Array<Hook<any, any>> = []; // 保存上一次执行的hook
oldState: any = null;
oldHooks: Array<Hook<any, any>> | null; // 保存上一次执行的hook
oldState: any;
oldRef: RefType | ((handle: any) => void) | null = null;
suspenseChildThrow = false;
oldSuspenseChildStatus: string = ''; // 上一次Suspense的Children是否显示
suspenseChildThrow: boolean;
oldSuspenseChildStatus: string; // 上一次Suspense的Children是否显示
oldChild: VNode | null = null;
suspenseDidCapture: boolean = false; // suspense是否捕获了异常
promiseResolve: boolean = false; // suspense的promise是否resolve
suspenseDidCapture: boolean; // suspense是否捕获了异常
promiseResolve: boolean; // suspense的promise是否resolve
path: Array<number> = []; // 保存从根到本节点的路径
toUpdateNodes: Set<VNode> | null = null; // 保存要更新的节点
path: string = ''; // 保存从根到本节点的路径
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode处理ref的时候使用
@ -85,18 +73,80 @@ export class VNode {
this.props = props;
// 根节点
if (tag === TreeRoot) {
this.outerDom = outerDom;
this.task = null;
this.toUpdateNodes = new Set<VNode>();
switch (tag) {
case TreeRoot:
this.outerDom = outerDom;
this.task = null;
this.toUpdateNodes = new Set<VNode>();
this.realNode = null;
this.updates = null;
this.stateCallbacks = null;
this.state = null;
this.oldState = null;
this.contexts = null;
break;
case FunctionComponent:
this.effectList = null;
this.hooks = null;
this.depContexts = null;
this.isDepContextChange = false;
this.oldHooks = null;
break;
case ClassComponent:
this.realNode = null;
this.updates = null;
this.stateCallbacks = null;
this.isForceUpdate = false;
this.state = null;
this.depContexts = null;
this.isDepContextChange = false;
this.oldState = null;
this.contexts = null;
break;
case ClsOrFunComponent:
this.realNode = null;
this.contexts = null;
break;
case DomPortal:
this.realNode = null;
this.contexts = null;
break;
case DomComponent:
this.realNode = null;
this.changeList = null;
this.contexts = null;
break;
case DomText:
this.realNode = null;
break;
case SuspenseComponent:
this.realNode = null;
this.suspensePromises = null;
this.suspenseChildThrow = false;
this.suspenseDidCapture = false;
this.promiseResolve = false;
this.oldSuspenseChildStatus = '';
break;
case ContextProvider:
this.contexts = null;
break;
case MemoComponent:
this.effectList = null;
break;
case LazyComponent:
this.realNode = null;
this.stateCallbacks = null;
break;
case Fragment:
break;
case ContextConsumer:
break;
case ForwardRef:
break;
case Profiler:
break;
case IncompleteClassComponent:
break;
}
}
setContext(contextName, value) {
this.contexts[contextName] = value;
}
getContext(contextName) {
return this.contexts[contextName];
}
}

View File

@ -78,7 +78,7 @@ export function updateVNode(vNode: VNode, vNodeProps?: any): VNode {
vNode.oldRef = vNode.ref;
FlagUtils.setNoFlags(vNode);
vNode.dirtyNodes = [];
vNode.dirtyNodes = null;
vNode.isCreated = false;
return vNode;
@ -133,9 +133,8 @@ export function createUndeterminedVNode(type, key, props) {
vNode.type = type;
vNode.shouldUpdate = true;
// lazy类型的特殊处理
vNode.isLazyComponent = isLazy;
if (isLazy) {
vNode.isLazyComponent = isLazy;
vNode.lazyType = type;
}
return vNode;
@ -143,7 +142,7 @@ export function createUndeterminedVNode(type, key, props) {
export function createTreeRootVNode(container) {
const vNode = newVirtualNode(TreeRoot, null, null, container);
vNode.path.push(0);
vNode.path += 0;
createUpdateArray(vNode);
return vNode;
}
@ -155,7 +154,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) {
case TreeRoot:
// 创建treeRoot
vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]);
vNode.path.push(0);
vNode.path += 0;
createUpdateArray(vNode);
break;
@ -165,7 +164,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) {
}
export function updateVNodePath(vNode: VNode) {
vNode.path = [...vNode.parent.path, vNode.cIndex];
vNode.path = vNode.parent.path + vNode.cIndex;
}
export function createVNodeFromElement(element: JSXElement): VNode {

View File

@ -4,97 +4,79 @@
import type { VNode } from '../Types';
export const InitFlag = /** */ 0b000000000000;
// vNode节点的flags
export const Addition = 'Addition';
export const Update = 'Update';
export const Deletion = 'Deletion';
export const ResetText = 'ResetText';
export const Callback = 'Callback';
export const DidCapture = 'DidCapture';
export const Ref = 'Ref';
export const Snapshot = 'Snapshot';
// 被中断了抛出错误的vNode以及它的父vNode
export const Interrupted = 'Interrupted';
export const ShouldCapture = 'ShouldCapture';
// For suspense
export const ForceUpdate = 'ForceUpdate';
export const Clear = 'Clear';
const FlagArr = [Addition, Update, Deletion, Clear, ResetText, Callback,
DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate];
const LifecycleEffectArr = [Update, Callback, Ref, Snapshot];
function resetFlag(node) {
node.flags = {};
}
export const Addition = /** */ 0b100000000000;
export const Update = /** */ 0b010000000000;
export const Deletion = /** */ 0b001000000000;
export const ResetText =/** */ 0b000100000000;
export const Callback = /** */ 0b000010000000;
export const DidCapture =/** */ 0b000001000000;
export const Ref = /** */ 0b000000100000;
export const Snapshot = /** */ 0b000000010000;
export const Interrupted = /** */ 0b000000001000; // 被中断了抛出错误的vNode以及它的父vNode
export const ShouldCapture =/** */ 0b000000000100;
export const ForceUpdate = /** */ 0b000000000010; // For suspense
export const Clear = /** */ 0b000000000001;
const LifecycleEffectArr = Update | Callback | Ref | Snapshot;
export class FlagUtils {
static removeFlag(node: VNode, flag: string) {
node.flags[flag] = false;
static removeFlag(node: VNode, flag: number) {
const flags = node.flags;
node.flags = flags & (~flag);
}
static removeLifecycleEffectFlags(node) {
LifecycleEffectArr.forEach(key => {
node.flags[key] = false;
});
const flags = node.flags;
node.flags = flags & (~LifecycleEffectArr);
}
static hasAnyFlag(node: VNode) { // 有标志位
const flags = node.flags;
const arrLength = FlagArr.length;
let key;
for (let i = 0; i < arrLength; i++) {
key = FlagArr[i];
if (flags[key]) {
return true;
}
}
return false;
return node.flags !== InitFlag;
}
static setNoFlags(node: VNode) {
resetFlag(node);
node.flags = InitFlag;
}
static markAddition(node: VNode) {
node.flags.Addition = true;
node.flags |= Addition;
}
static setAddition(node: VNode) {
resetFlag(node);
node.flags.Addition = true;
node.flags = Addition;
}
static markUpdate(node: VNode) {
node.flags.Update = true;
node.flags |= Update;
}
static setDeletion(node: VNode) {
resetFlag(node);
node.flags.Deletion = true;
node.flags = Deletion;
}
static markContentReset(node: VNode) {
node.flags.ResetText = true;
node.flags |= ResetText;
}
static markCallback(node: VNode) {
node.flags.Callback = true;
node.flags |= Callback;
}
static markDidCapture(node: VNode) {
node.flags.DidCapture = true;
node.flags |= DidCapture;
}
static markShouldCapture(node: VNode) {
node.flags.ShouldCapture = true;
node.flags |= ShouldCapture;
}
static markRef(node: VNode) {
node.flags.Ref = true;
node.flags |= Ref;
}
static markSnapshot(node: VNode) {
node.flags.Snapshot = true;
node.flags |= Snapshot;
}
static markInterrupted(node: VNode) {
node.flags.Interrupted = true;
node.flags |= Interrupted;
}
static markForceUpdate(node: VNode) {
node.flags.ForceUpdate = true;
node.flags |= ForceUpdate;
}
static markClear(node: VNode) {
node.flags.Clear = true;
node.flags |= Clear;
}
}

View File

@ -7,10 +7,7 @@ import type {VNode} from '../Types';
import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags';
import {isComment} from '../../dom/utils/Common';
import {getNearestVNode} from '../../dom/DOMInternalKeys';
export function getSiblingVNode(node) {
return node.next;
}
import { Addition, InitFlag } from './VNodeFlags';
export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) {
let node: VNode | null = beginVNode;
@ -58,7 +55,7 @@ export function travelVNodeTree(
}
// 找兄弟,没有就往上再找兄弟
while (getSiblingVNode(node) === null) {
while (node.next === null) {
if (node.parent === null || node.parent === overVNode) {
return null;
}
@ -69,7 +66,7 @@ export function travelVNodeTree(
}
}
// 找到兄弟
const siblingVNode = getSiblingVNode(node);
const siblingVNode = node.next;
siblingVNode.parent = node.parent;
node = siblingVNode;
}
@ -79,28 +76,25 @@ export function travelVNodeTree(
export function clearVNode(vNode: VNode) {
vNode.child = null;
vNode.next = null;
vNode.depContexts = [];
vNode.dirtyNodes = [];
vNode.depContexts = null;
vNode.dirtyNodes = null;
vNode.state = null;
vNode.hooks = [];
vNode.suspenseChildStatus = '';
vNode.hooks = null;
vNode.props = null;
vNode.parent = null;
vNode.suspensePromises = null;
vNode.changeList = null;
vNode.effectList = [];
vNode.effectList = null;
vNode.updates = null;
vNode.realNode = null;
vNode.oldProps = null;
vNode.oldHooks = [];
vNode.oldHooks = null;
vNode.oldState = null;
vNode.oldRef = null;
vNode.suspenseChildThrow = false;
vNode.oldSuspenseChildStatus = '';
vNode.oldChild = null;
vNode.flags = InitFlag;
vNode.path = [];
vNode.toUpdateNodes = null;
vNode.belongClassVNode = null;
@ -179,7 +173,7 @@ export function getSiblingDom(vNode: VNode): Element | null {
findSibling: while (true) {
// 没有兄弟节点,找父节点
while (getSiblingVNode(node) === null) {
while (node.next === null) {
// 没父节点,或父节点已经是根节点,则返回
if (node.parent === null || isDomContainer(node.parent)) {
return null;
@ -187,14 +181,14 @@ export function getSiblingDom(vNode: VNode): Element | null {
node = node.parent;
}
const siblingVNode = getSiblingVNode(node);
const siblingVNode = node.next;
siblingVNode.parent = node.parent;
node = siblingVNode;
// 如果不是dom节点往下找
while (!isDomVNode(node)) {
// 如果节点也是Addition
if (node.flags.Addition) {
if ((node.flags & Addition) ===Addition) {
continue findSibling;
}
@ -208,7 +202,7 @@ export function getSiblingDom(vNode: VNode): Element | null {
}
}
if (!node.flags.Addition) {
if ((node.flags & Addition) ===InitFlag) {
// 找到
return node.realNode;
}