From aa1944e8d45bbf13bdc614d079e96ffa461d4594 Mon Sep 17 00:00:00 2001 From: * <8> Date: Fri, 28 Jan 2022 10:19:57 +0800 Subject: [PATCH 01/35] Match-id-79434802c4c9b64f0a228c6c1b1793fea390b22e --- libs/horizon/src/renderer/submit/LifeCycleHandler.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index ecaa6298..0ca8b0a8 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -336,7 +336,12 @@ function submitClear(vNode: VNode): void { // 在所有子项都卸载后,删除dom树中的节点 removeChildDom(currentParent, vNode.realNode); - currentParent.append(cloneDom); + const realNodeNext = getSiblingDom(vNode); + if (realNodeNext) { + insertDomBefore(currentParent, cloneDom, realNodeNext); + } else { + appendChildElement(currentParent, cloneDom); + } vNode.realNode = cloneDom; attachRef(vNode); FlagUtils.removeFlag(vNode, Clear); From 75289ee0853555b8f5267b14a19c7ecc52400d74 Mon Sep 17 00:00:00 2001 From: * <8> Date: Fri, 28 Jan 2022 10:54:06 +0800 Subject: [PATCH 02/35] Match-id-3af6008f5308a6c047b9f9a878e9990b606326bd --- .../src/renderer/submit/LifeCycleHandler.ts | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 0ca8b0a8..41c16cb6 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -252,11 +252,7 @@ function insertOrAppendPlacementNode( const { tag, realNode } = node; if (isDomVNode(node)) { - if (beforeDom) { - insertDomBefore(parent, realNode, beforeDom); - } else { - appendChildElement(parent, realNode); - } + insertDom(parent, realNode, beforeDom); } else if (tag === DomPortal) { // 这里不做处理,直接在portal中处理 } else { @@ -269,6 +265,14 @@ function insertOrAppendPlacementNode( } } +function insertDom(parent, realNode, beforeDom) { + if (beforeDom) { + insertDomBefore(parent, realNode, beforeDom); + } else { + appendChildElement(parent, realNode); + } +} + // 遍历所有子节点:删除dom节点,detach ref 和 调用componentWillUnmount() function unmountDomComponents(vNode: VNode): void { let currentParentIsValid = false; @@ -337,11 +341,7 @@ function submitClear(vNode: VNode): void { // 在所有子项都卸载后,删除dom树中的节点 removeChildDom(currentParent, vNode.realNode); const realNodeNext = getSiblingDom(vNode); - if (realNodeNext) { - insertDomBefore(currentParent, cloneDom, realNodeNext); - } else { - appendChildElement(currentParent, cloneDom); - } + insertDom(currentParent, cloneDom, realNodeNext); vNode.realNode = cloneDom; attachRef(vNode); FlagUtils.removeFlag(vNode, Clear); From da61dcb520a194063e604a5b7d120ddf961e3ae6 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 16 Feb 2022 17:32:31 +0800 Subject: [PATCH 03/35] Match-id-77abf3fc5441d3da74ce4a05278ae87af13e4421 --- babel.config.js | 2 +- libs/horizon/src/event/HorizonEventMain.ts | 2 +- .../src/event/customEvents/CustomBaseEvent.ts | 108 +++++------------- .../src/event/customEvents/EventFactory.ts | 3 +- .../BeforeInputEventHandler.ts | 1 - .../simulatedEvtHandler/ChangeEventHandler.ts | 1 - .../CompositionEventHandler.ts | 1 - .../SelectionEventHandler.ts | 1 - 8 files changed, 32 insertions(+), 87 deletions(-) diff --git a/babel.config.js b/babel.config.js index eebb794c..b052c6f3 100644 --- a/babel.config.js +++ b/babel.config.js @@ -22,7 +22,7 @@ module.exports = { ['@babel/plugin-transform-spread', { loose: true, useBuiltIns: true }], '@babel/plugin-transform-parameters', ['@babel/plugin-transform-destructuring', { loose: true, useBuiltIns: true }], - ['@babel/plugin-transform-block-scoping', { throwIfClosureRequired: true }], + ['@babel/plugin-transform-block-scoping', { throwIfClosureRequired: false }], '@babel/plugin-transform-classes', '@babel/plugin-transform-runtime', '@babel/plugin-proposal-nullish-coalescing-operator', diff --git a/libs/horizon/src/event/HorizonEventMain.ts b/libs/horizon/src/event/HorizonEventMain.ts index 9a9e2719..3f319045 100644 --- a/libs/horizon/src/event/HorizonEventMain.ts +++ b/libs/horizon/src/event/HorizonEventMain.ts @@ -47,7 +47,7 @@ function getCommonListeners( nativeEvtName = 'blur'; } - const horizonEvent = createCustomEvent(horizonEvtName, nativeEvtName, nativeEvent, null, target); + const horizonEvent = createCustomEvent(horizonEvtName, nativeEvtName, nativeEvent, target); return getListenersFromTree( vNode, horizonEvtName, diff --git a/libs/horizon/src/event/customEvents/CustomBaseEvent.ts b/libs/horizon/src/event/customEvents/CustomBaseEvent.ts index e9ca60df..299a754d 100644 --- a/libs/horizon/src/event/customEvents/CustomBaseEvent.ts +++ b/libs/horizon/src/event/customEvents/CustomBaseEvent.ts @@ -2,31 +2,6 @@ * 自定义的基本事件类型 */ -import {VNode} from '../../renderer/Types'; - -// 从原生事件中复制属性到自定义事件中 -function extendAttribute(target, source) { - let val; - let attr; - for (attr in source) { - // 这两个方法需要override - if (attr === 'preventDefault' || attr === 'stopPropagation') { - continue; - } - - val = source[attr]; - if (val !== undefined) { - if (typeof val === 'function') { - target[attr] = function() { - return source[attr].apply(source, arguments); - }; - } else { - target[attr] = source[attr]; - } - } - } -} - // 兼容IE的event key const uniqueKeyMap = new Map([ ['Esc', 'Escape'], @@ -38,47 +13,50 @@ const uniqueKeyMap = new Map([ ['Del', 'Delete'], ]); +// 从原生事件中复制属性到自定义事件中 +function extendAttribute(target, source) { + let val; + let attr; + for (attr in source) { + val = source[attr]; + if (val !== undefined) { + if (typeof val === 'function') { + let fun = source[attr]; + target[attr] = function() { + return fun.apply(source, arguments); + }; + } else { + target[attr] = val; + } + } + } +} + export class CustomBaseEvent { - defaultPrevented: boolean; - target: EventTarget; isDefaultPrevented: () => boolean; isPropagationStopped: () => boolean; - currentTarget: EventTarget; - relatedTarget: EventTarget; - - // custom事件自定义属性 - customEventName: string; - targetVNode: VNode; - type: string; - timeStamp: number; - nativeEvent: any; + target: EventTarget | null; // 键盘事件属性 key: string; - charCode: number; - keyCode: number; - which: number; + + // custom事件自定义属性 + customEventName: string; + type: string; + nativeEvent: any; constructor( - customEvtName: string | null, + customEvtName: string, nativeEvtName: string, nativeEvt: { [propName: string]: any }, - vNode: VNode | null, - target: null | EventTarget + target: EventTarget | null ) { // 复制原生属性到自定义事件 extendAttribute(this, nativeEvt); - const defaultPrevented = nativeEvt.defaultPrevented != null ? - nativeEvt.defaultPrevented : - nativeEvt.returnValue === false; - this.defaultPrevented = defaultPrevented; - this.preventDefault = this.preventDefault.bind(this); - this.stopPropagation = this.stopPropagation.bind(this); - this.isDefaultPrevented = () => defaultPrevented; - this.isPropagationStopped = () => false; - this.relatedTarget = nativeEvt.relatedTarget; + this.isDefaultPrevented = () => nativeEvt.defaultPrevented; + this.isPropagationStopped = () => nativeEvt.cancelBubble; this.target = target; // 键盘事件属性 @@ -86,35 +64,7 @@ export class CustomBaseEvent { // custom事件自定义属性 this.customEventName = customEvtName; - this.targetVNode = vNode; this.type = nativeEvtName; this.nativeEvent = nativeEvt; } - - // 阻止默认行为 - preventDefault() { - this.defaultPrevented = true; - if (!this.nativeEvent) { - return; - } - - if (typeof this.nativeEvent.preventDefault === 'function') { - this.nativeEvent.preventDefault(); - } - this.nativeEvent.returnValue = false; - this.isDefaultPrevented = () => true; - } - - // 停止冒泡 - stopPropagation() { - if (!this.nativeEvent) { - return; - } - - if (typeof this.nativeEvent.stopPropagation === 'function') { - this.nativeEvent.stopPropagation(); - } - this.nativeEvent.cancelBubble = true; - this.isPropagationStopped = () => true; - } } diff --git a/libs/horizon/src/event/customEvents/EventFactory.ts b/libs/horizon/src/event/customEvents/EventFactory.ts index 59f606ee..c92a8aaa 100644 --- a/libs/horizon/src/event/customEvents/EventFactory.ts +++ b/libs/horizon/src/event/customEvents/EventFactory.ts @@ -1,12 +1,11 @@ import {CustomBaseEvent} from './CustomBaseEvent'; // 创建普通自定义事件对象实例,和原生事件对应 -export function createCustomEvent(customEventName, nativeEvtName, nativeEvent, vNode, currentTarget) { +export function createCustomEvent(customEventName, nativeEvtName, nativeEvent, currentTarget) { return new CustomBaseEvent( customEventName, nativeEvtName, nativeEvent, - vNode, currentTarget, ); } diff --git a/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts index 2ab0fc07..3d26a9a4 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts @@ -40,7 +40,6 @@ export function getListeners( 'onBeforeInput', 'beforeinput', nativeEvent, - null, target, ); event.data = chars; diff --git a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts index 9c2040c2..b521f7cd 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts @@ -52,7 +52,6 @@ export function getListeners( 'onChange', 'change', nativeEvt, - null, target, ); return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL); diff --git a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts index be3a38f1..a7394f5c 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts @@ -24,7 +24,6 @@ export function getListeners( evtType, evtName, nativeEvt, - null, target, ); return getListenersFromTree(vNode, evtType, event, EVENT_TYPE_ALL); diff --git a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts index c5a807c4..f32cc4b2 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts @@ -58,7 +58,6 @@ function getSelectEvent(nativeEvent, target) { horizonEventName, 'select', nativeEvent, - null, target, ); event.target = currentElement; From 290f2097c5a8a5e16da239d14280bb736f74ee7b Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 10:52:12 +0800 Subject: [PATCH 04/35] Match-id-5cdfec2ac913c704d26e3fc47a3d41f0c6d6382f --- libs/horizon/src/renderer/vnode/VNode.ts | 12 ++++++------ libs/horizon/src/renderer/vnode/VNodeUtils.ts | 14 +++++--------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index e5a848de..9c9fd8e2 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -25,17 +25,17 @@ export class VNode { suspensePromises: any = null; // suspense组件的promise列表 changeList: any = null; // DOM的变更列表 - effectList: any[] = []; // useEffect 的更新数组 + effectList: any[] | null = []; // useEffect 的更新数组 updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组 - stateCallbacks: any[] = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 + stateCallbacks: any[] | null = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 isForceUpdate: boolean = false; // 是否使用强制更新 state: any = null; // ClassComponent和TreeRoot的状态 - hooks: Array> = []; // 保存hook + hooks: Array> | null = []; // 保存hook suspenseChildStatus: string = ''; // Suspense的Children是否显示 - depContexts: Array> = []; // FunctionComponent和ClassComponent对context的依赖列表 + depContexts: Array> | null = []; // FunctionComponent和ClassComponent对context的依赖列表 isDepContextChange: boolean = false; // context是否变更 - dirtyNodes: Array = []; // 需要改动的节点数组 + dirtyNodes: Array | null = []; // 需要改动的节点数组 shouldUpdate: boolean = false; childShouldUpdate: boolean = false; outerDom: any; @@ -65,7 +65,7 @@ export class VNode { clearChild: VNode | null = null; // one tree相关属性 isCreated: boolean = true; - oldHooks: Array> = []; // 保存上一次执行的hook + oldHooks: Array> | null = []; // 保存上一次执行的hook oldState: any = null; oldRef: RefType | ((handle: any) => void) | null = null; suspenseChildThrow = false; diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index dc38b93e..82ad3ec8 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -79,28 +79,24 @@ 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.path = []; vNode.toUpdateNodes = null; vNode.belongClassVNode = null; From 3f08ed229f0a77a028b94e0b467554bf5c8f97da Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 10:55:53 +0800 Subject: [PATCH 05/35] Match-id-a4195774976a6bab660ca01ecef0e20e8c93baf6 --- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- libs/horizon/src/renderer/vnode/VNodeCreator.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 9c9fd8e2..0270165b 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -74,7 +74,7 @@ export class VNode { suspenseDidCapture: boolean = false; // suspense是否捕获了异常 promiseResolve: boolean = false; // suspense的promise是否resolve - path: Array = []; // 保存从根到本节点的路径 + path: string = ''; // 保存从根到本节点的路径 toUpdateNodes: Set | null = null; // 保存要更新的节点 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 11abe1b1..40b5cc97 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -143,7 +143,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 +155,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 +165,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 { From 9a1b0add4be9694efdaf9d9072d1f573b09d5460 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:08:43 +0800 Subject: [PATCH 06/35] Match-id-008af88bfa5eb7487150476ddae80d57f9c57b0a --- libs/horizon/src/renderer/ErrorHandler.ts | 2 +- libs/horizon/src/renderer/TreeBuilder.ts | 14 ++++++++++++-- .../src/renderer/diff/nodeDiffComparator.ts | 4 ++++ libs/horizon/src/renderer/submit/Submit.ts | 10 +++++++--- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- libs/horizon/src/renderer/vnode/VNodeCreator.ts | 2 +- 6 files changed, 26 insertions(+), 8 deletions(-) diff --git a/libs/horizon/src/renderer/ErrorHandler.ts b/libs/horizon/src/renderer/ErrorHandler.ts index 3c3305c1..991ef861 100644 --- a/libs/horizon/src/renderer/ErrorHandler.ts +++ b/libs/horizon/src/renderer/ErrorHandler.ts @@ -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') { diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 3c9b729b..9ff1cd0d 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -57,10 +57,20 @@ function resetProcessingVariables(startUpdateVNode: VNode) { // 收集有变化的节点,在submit阶段继续处理 function collectDirtyNodes(vNode: VNode, parent: VNode): void { // 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。 - parent.dirtyNodes.push(...vNode.dirtyNodes); + if (vNode.dirtyNodes !== null && vNode.dirtyNodes.length) { + if (parent.dirtyNodes === null) { + parent.dirtyNodes = [...vNode.dirtyNodes]; + } else { + parent.dirtyNodes.push(...vNode.dirtyNodes); + } + } if (FlagUtils.hasAnyFlag(vNode)) { - parent.dirtyNodes.push(vNode); + if (parent.dirtyNodes === null) { + parent.dirtyNodes = [vNode]; + } else { + parent.dirtyNodes.push(vNode); + } } } diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index 797687b5..0d65c816 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -27,6 +27,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); } diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index e222564f..7fccbe41 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -40,11 +40,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 +64,7 @@ export function submitToRender(treeRoot) { // after submit阶段 afterSubmit(dirtyNodes); - setExecuteMode(preMode) + setExecuteMode(preMode); } if (isSchedulingEffects()) { diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 0270165b..c875fe5a 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -35,7 +35,7 @@ export class VNode { suspenseChildStatus: string = ''; // Suspense的Children是否显示 depContexts: Array> | null = []; // FunctionComponent和ClassComponent对context的依赖列表 isDepContextChange: boolean = false; // context是否变更 - dirtyNodes: Array | null = []; // 需要改动的节点数组 + dirtyNodes: Array | null = null; // 需要改动的节点数组 shouldUpdate: boolean = false; childShouldUpdate: boolean = false; outerDom: any; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 40b5cc97..2d6d3bb2 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -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; From 32d31738b71edf23dc05bf28e4f69801b607e7cf Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:12:47 +0800 Subject: [PATCH 07/35] Match-id-07694f7bc016fe0cfd4ed0c37eae556bdf18cc58 --- libs/horizon/src/renderer/TreeBuilder.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 9ff1cd0d..020b58b2 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -57,12 +57,15 @@ function resetProcessingVariables(startUpdateVNode: VNode) { // 收集有变化的节点,在submit阶段继续处理 function collectDirtyNodes(vNode: VNode, parent: VNode): void { // 将子树和此vNode的所有效果附加到父树的效果列表中,子项的完成顺序会影响副作用顺序。 - if (vNode.dirtyNodes !== null && vNode.dirtyNodes.length) { + 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)) { From 21e1ab6595da8c0233794b25aecf985d82f3f39c Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:17:20 +0800 Subject: [PATCH 08/35] Match-id-76c4bd08e76f99dec2a23ee3bb9ce802c95eebe1 --- libs/horizon/src/renderer/submit/Submit.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index 7fccbe41..30fee9d8 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -65,6 +65,8 @@ export function submitToRender(treeRoot) { afterSubmit(dirtyNodes); setExecuteMode(preMode); + dirtyNodes.length = 0; + startVNode.dirtyNodes = null; } if (isSchedulingEffects()) { From c702a1b3cb492fd9e4de8acd4bd11bc63ab0527a Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:21:16 +0800 Subject: [PATCH 09/35] Match-id-a7deb6aa15e1e093aabaadcff3b378abd79319d7 --- .../src/renderer/submit/HookEffectHandler.ts | 99 ++++++++++--------- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 2 files changed, 53 insertions(+), 48 deletions(-) diff --git a/libs/horizon/src/renderer/submit/HookEffectHandler.ts b/libs/horizon/src/renderer/submit/HookEffectHandler.ts index b6706389..f1811d93 100644 --- a/libs/horizon/src/renderer/submit/HookEffectHandler.ts +++ b/libs/horizon/src/renderer/submit/HookEffectHandler.ts @@ -27,23 +27,24 @@ export function isSchedulingEffects() { export function callUseEffects(vNode: VNode) { const effectList: EffectList = vNode.effectList; - - 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 (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); + + // 异步调用 + 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; - - effectList.forEach(effect => { - const {removeEffect, effectConstant} = effect; - - if (removeEffect !== undefined) { - if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect,就异步调用 - hookRemoveEffects.push(effect); - - if (!isScheduling) { - isScheduling = true; - runAsync(runAsyncEffects); + if (effectList !== null) { + effectList.forEach(effect => { + const {removeEffect, effectConstant} = effect; + + if (removeEffect !== undefined) { + if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect,就异步调用 + hookRemoveEffects.push(effect); + + 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(); + } + }); + } } diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index c875fe5a..313b5a61 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -25,7 +25,7 @@ export class VNode { suspensePromises: any = null; // suspense组件的promise列表 changeList: any = null; // DOM的变更列表 - effectList: any[] | null = []; // useEffect 的更新数组 + effectList: any[] | null = null; // useEffect 的更新数组 updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组 stateCallbacks: any[] | null = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 isForceUpdate: boolean = false; // 是否使用强制更新 From 52537bdf93e409b6ad062057af2808b8051de96b Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:22:50 +0800 Subject: [PATCH 10/35] Match-id-83bf820362983ac9c398f7308262c169b259c898 --- libs/horizon/src/dom/utils/Common.ts | 18 +----- libs/horizon/src/event/HorizonEventMain.ts | 4 +- libs/horizon/src/event/StyleEventNames.ts | 55 ------------------- libs/horizon/src/event/const.ts | 22 +++----- .../simulatedEvtHandler/ChangeEventHandler.ts | 10 ++-- .../CompositionEventHandler.ts | 6 +- .../SelectionEventHandler.ts | 17 +++--- libs/horizon/src/event/utils.ts | 14 ++--- 8 files changed, 34 insertions(+), 112 deletions(-) delete mode 100644 libs/horizon/src/event/StyleEventNames.ts diff --git a/libs/horizon/src/dom/utils/Common.ts b/libs/horizon/src/dom/utils/Common.ts index 8de8f7c4..09602c82 100644 --- a/libs/horizon/src/dom/utils/Common.ts +++ b/libs/horizon/src/dom/utils/Common.ts @@ -6,21 +6,9 @@ import {Props} from '../DOMOperator'; * @param doc 指定 document */ export function getFocusedDom(doc?: Document): HorizonDom | null { - let currentDocument; - if (doc) { - currentDocument = doc; - } else { - if (document) { - currentDocument = document; - } - } - if (!currentDocument) { - return null; - } else if (currentDocument.activeElement) { - return currentDocument.activeElement; - } else { - return currentDocument.body; - } + let currentDocument = doc ?? document; + + return currentDocument.activeElement ?? currentDocument.body; } // 如果 input 或者 textarea 元素中有文字被选中时,activeElement 属性就会返回该元素 diff --git a/libs/horizon/src/event/HorizonEventMain.ts b/libs/horizon/src/event/HorizonEventMain.ts index 3f319045..deabece1 100644 --- a/libs/horizon/src/event/HorizonEventMain.ts +++ b/libs/horizon/src/event/HorizonEventMain.ts @@ -69,7 +69,7 @@ function processListeners(listenerList: ListenerUnitList): void { }); } -function getProcessListenersFacade( +function getProcessListeners( nativeEvtName: string, vNode: VNode | null, nativeEvent: AnyNativeEvent, @@ -138,7 +138,7 @@ function triggerHorizonEvents( const nativeEventTarget = nativeEvent.target || nativeEvent.srcElement; // 获取委托事件队列 - const listenerList = getProcessListenersFacade(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture); + const listenerList = getProcessListeners(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture); // 处理触发的事件队列 processListeners(listenerList); diff --git a/libs/horizon/src/event/StyleEventNames.ts b/libs/horizon/src/event/StyleEventNames.ts deleted file mode 100644 index d2bf85b1..00000000 --- a/libs/horizon/src/event/StyleEventNames.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * style中的动画事件 - */ - -// style事件浏览器兼容前缀 -const vendorPrefixes = { - animationend: { - MozAnimation: 'mozAnimationEnd', - WebkitAnimation: 'webkitAnimationEnd', - animation: 'animationend', - }, - animationiteration: { - MozAnimation: 'mozAnimationIteration', - WebkitAnimation: 'webkitAnimationIteration', - animation: 'animationiteration', - }, - animationstart: { - MozAnimation: 'mozAnimationStart', - WebkitAnimation: 'webkitAnimationStart', - animation: 'animationstart', - }, - transitionend: { - MozTransition: 'mozTransitionEnd', - WebkitTransition: 'webkitTransitionEnd', - transition: 'transitionend', - }, -}; - -// 获取属性中对应事件名 -function getEventNameByStyle(eventName) { - const prefixMap = vendorPrefixes[eventName]; - if (!prefixMap) { - return eventName; - } - const style = document.createElement('div').style - for (const styleProp in prefixMap) { - if (styleProp in style) { - return prefixMap[styleProp]; - } - } - return eventName; -} - -export const STYLE_AMT_END: string = getEventNameByStyle( - 'animationend', -); -export const STYLE_AMT_ITERATION: string = getEventNameByStyle( - 'animationiteration', -); -export const STYLE_AMT_START: string = getEventNameByStyle( - 'animationstart', -); -export const STYLE_TRANS_END: string = getEventNameByStyle( - 'transitionend', -); diff --git a/libs/horizon/src/event/const.ts b/libs/horizon/src/event/const.ts index 75bea89f..a3c2805e 100644 --- a/libs/horizon/src/event/const.ts +++ b/libs/horizon/src/event/const.ts @@ -1,9 +1,3 @@ -import { - STYLE_AMT_END, - STYLE_AMT_ITERATION, - STYLE_AMT_START, - STYLE_TRANS_END -} from './StyleEventNames'; // Horizon事件和原生事件对应关系 export const horizonEventToNativeMap = new Map([ @@ -38,10 +32,10 @@ export const horizonEventToNativeMap = new Map([ ['onSelect', ['focusout', 'contextmenu', 'dragend', 'focusin', 'keydown', 'keyup', 'mousedown', 'mouseup', 'selectionchange']], - ['onAnimationEnd', [STYLE_AMT_END]], - ['onAnimationIteration', [STYLE_AMT_ITERATION]], - ['onAnimationStart', [STYLE_AMT_START]], - ['onTransitionEnd', [STYLE_TRANS_END]] + ['onAnimationEnd', ['animationend']], + ['onAnimationIteration', ['animationiteration']], + ['onAnimationStart', ['animationstart']], + ['onTransitionEnd', ['transitionend']] ]); export const CommonEventToHorizonMap = { @@ -68,10 +62,10 @@ export const CommonEventToHorizonMap = { selectionchange: 'selectChange', textInput: 'textInput', touchmove: 'touchMove', - [STYLE_AMT_END]: 'animationEnd', - [STYLE_AMT_ITERATION]: 'animationIteration', - [STYLE_AMT_START]: 'animationStart', - [STYLE_TRANS_END]: 'transitionEnd', + animationend: 'animationEnd', + animationiteration: 'animationIteration', + animationstart: 'animationStart', + transitionend: 'transitionEnd', }; export const CHAR_CODE_ENTER = 13; diff --git a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts index b521f7cd..7a0ca02f 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts @@ -2,7 +2,7 @@ import {createCustomEvent} from '../customEvents/EventFactory'; import {getDom} from '../../dom/DOMInternalKeys'; import {isInputValueChanged} from '../../dom/valueHandler/ValueChangeHandler'; import {addValueUpdateList} from '../ControlledValueUpdater'; -import {isTextInputElement} from '../utils'; +import {isInputElement} from '../utils'; import {EVENT_TYPE_ALL} from '../const'; import {AnyNativeEvent, ListenerUnitList} from '../Types'; import { @@ -18,14 +18,14 @@ function shouldTriggerChangeEvent(targetDom, evtName) { if (domTag === 'select' || (domTag === 'input' && type === 'file')) { return evtName === 'change'; - } else if (isTextInputElement(targetDom)) { - if (evtName === 'input' || evtName === 'change') { - return isInputValueChanged(targetDom); - } } else if (domTag === 'input' && (type === 'checkbox' || type === 'radio')) { if (evtName === 'click') { return isInputValueChanged(targetDom); } + } else if (isInputElement(targetDom)) { + if (evtName === 'input' || evtName === 'change') { + return isInputValueChanged(targetDom); + } } return false; } diff --git a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts index a7394f5c..9dd8731c 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts @@ -13,16 +13,16 @@ const compositionEventObj = { // compoisition事件主要处理中文输入法输入时的触发事件 export function getListeners( - evtName: string, + nativeEvtName: string, nativeEvt: AnyNativeEvent, vNode: null | VNode, target: null | EventTarget, ): ListenerUnitList { - const evtType = compositionEventObj[evtName]; + const evtType = compositionEventObj[nativeEvtName]; const event = createCustomEvent( evtType, - evtName, + nativeEvtName, nativeEvt, target, ); diff --git a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts index f32cc4b2..778a3b82 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts @@ -3,21 +3,21 @@ import {shallowCompare} from '../../renderer/utils/compare'; import {getFocusedDom} from '../../dom/utils/Common'; import {getDom} from '../../dom/DOMInternalKeys'; import {isDocument} from '../../dom/utils/Common'; -import {isTextInputElement} from '../utils'; +import {isInputElement} from '../utils'; import type {AnyNativeEvent} from '../Types'; import {getListenersFromTree} from '../ListenerGetter'; import type {VNode} from '../../renderer/Types'; import {EVENT_TYPE_ALL} from '../const'; import {ListenerUnitList} from '../Types'; -const horizonEventName = 'onSelect' +const horizonEventName = 'onSelect'; let currentElement = null; let currentVNode = null; let lastSelection: Selection | null = null; function initTargetCache(dom, vNode) { - if (isTextInputElement(dom) || dom.contentEditable === 'true') { + if (isInputElement(dom) || dom.contentEditable === 'true') { currentElement = dom; currentVNode = vNode; lastSelection = null; @@ -79,23 +79,23 @@ function getSelectEvent(nativeEvent, target) { * 触发场景:用户输入、折叠选择、文本选择 */ export function getListeners( - name: string, + nativeEvtName: string, nativeEvt: AnyNativeEvent, vNode: null | VNode, target: null | EventTarget, ): ListenerUnitList { const targetNode = vNode ? getDom(vNode) : window; let eventUnitList: ListenerUnitList = []; - switch (name) { + switch (nativeEvtName) { case 'focusin': initTargetCache(targetNode, vNode); - return eventUnitList; + break; case 'focusout': clearTargetCache(); - return eventUnitList; + break; case 'mousedown': isInMouseEvent = true; - return eventUnitList; + break; case 'contextmenu': case 'mouseup': case 'dragend': @@ -107,5 +107,6 @@ export function getListeners( case 'keyup': eventUnitList = getSelectEvent(nativeEvt, target); } + return eventUnitList; } diff --git a/libs/horizon/src/event/utils.ts b/libs/horizon/src/event/utils.ts index 51f022f1..3909e7a8 100644 --- a/libs/horizon/src/event/utils.ts +++ b/libs/horizon/src/event/utils.ts @@ -1,15 +1,9 @@ -// 支持的输入框类型 -const supportedInputTypes = ['color', 'date', 'datetime', 'datetime-local', 'email', 'month', - 'number', 'password', 'range', 'search', 'tel', 'text', 'time', 'url', 'week']; - -export function isTextInputElement(dom?: HTMLElement): boolean { - if (dom instanceof HTMLInputElement) { - return supportedInputTypes.includes(dom.type); +export function isInputElement(dom?: HTMLElement): boolean { + if (dom instanceof HTMLInputElement || dom instanceof HTMLTextAreaElement) { + return true; } - - const nodeName = dom && dom.nodeName && dom.nodeName.toLowerCase(); - return nodeName === 'textarea'; + return false; } From 0a952e800a2c76c55ae625dedf95eb903853c9d4 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:23:58 +0800 Subject: [PATCH 11/35] Match-id-e6fbf97ee32697280c273be5bc3a8b5f1605f1c9 --- libs/horizon/src/renderer/UpdateHandler.ts | 6 +++++- .../src/renderer/submit/LifeCycleHandler.ts | 15 ++++++++------- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libs/horizon/src/renderer/UpdateHandler.ts b/libs/horizon/src/renderer/UpdateHandler.ts index d00f3ce9..a2b55485 100644 --- a/libs/horizon/src/renderer/UpdateHandler.ts +++ b/libs/horizon/src/renderer/UpdateHandler.ts @@ -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); + } } } diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index be4152d1..354a179e 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -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); + } + }); + } } // 调用界面变化后的生命周期 diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 313b5a61..bf4aca7e 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -27,7 +27,7 @@ export class VNode { changeList: any = null; // DOM的变更列表 effectList: any[] | null = null; // useEffect 的更新数组 updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组 - stateCallbacks: any[] | null = []; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 + stateCallbacks: any[] | null = null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组 isForceUpdate: boolean = false; // 是否使用强制更新 state: any = null; // ClassComponent和TreeRoot的状态 From b27cb830dc09b3b6d46fe2f047aeb0d52a967ad5 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:28:20 +0800 Subject: [PATCH 12/35] Match-id-b1728f3e2e13d0dceaec7d800af945630574e9f8 --- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index bf4aca7e..25b12511 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -31,7 +31,7 @@ export class VNode { isForceUpdate: boolean = false; // 是否使用强制更新 state: any = null; // ClassComponent和TreeRoot的状态 - hooks: Array> | null = []; // 保存hook + hooks: Array> | null = null; // 保存hook suspenseChildStatus: string = ''; // Suspense的Children是否显示 depContexts: Array> | null = []; // FunctionComponent和ClassComponent对context的依赖列表 isDepContextChange: boolean = false; // context是否变更 From 3410a9cc0047e2f6431ae6a6cbe65d0b277518c0 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:34:11 +0800 Subject: [PATCH 13/35] Match-id-2a4d49b90b105db41f89732a409a878541bd1263 --- .../src/renderer/components/context/Context.ts | 12 +++++++----- libs/horizon/src/renderer/render/ContextProvider.ts | 2 +- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/libs/horizon/src/renderer/components/context/Context.ts b/libs/horizon/src/renderer/components/context/Context.ts index bcbc4f83..4052a0ed 100644 --- a/libs/horizon/src/renderer/components/context/Context.ts +++ b/libs/horizon/src/renderer/components/context/Context.ts @@ -4,17 +4,19 @@ import {throwNotInFuncError} from '../../hooks/BaseHook'; // 重置依赖 export function resetDepContexts(vNode: VNode): void { - vNode.depContexts = []; + vNode.depContexts = null; } // 收集依赖 function collectDeps(vNode: VNode, context: ContextType) { 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); + } } } diff --git a/libs/horizon/src/renderer/render/ContextProvider.ts b/libs/horizon/src/renderer/render/ContextProvider.ts index c31a9ff4..c3c287d8 100644 --- a/libs/horizon/src/renderer/render/ContextProvider.ts +++ b/libs/horizon/src/renderer/render/ContextProvider.ts @@ -50,7 +50,7 @@ function handleContextChange(processing: VNode, context: ContextType): void // 从vNode开始遍历 travelVNodeTree(vNode, node => { const depContexts = node.depContexts; - if (depContexts.length) { + if (depContexts && depContexts.length) { isMatch = matchDependencies(depContexts, context, node) ?? isMatch; } }, node => diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 25b12511..8ce6d94b 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -33,7 +33,7 @@ export class VNode { state: any = null; // ClassComponent和TreeRoot的状态 hooks: Array> | null = null; // 保存hook suspenseChildStatus: string = ''; // Suspense的Children是否显示 - depContexts: Array> | null = []; // FunctionComponent和ClassComponent对context的依赖列表 + depContexts: Array> | null = null; // FunctionComponent和ClassComponent对context的依赖列表 isDepContextChange: boolean = false; // context是否变更 dirtyNodes: Array | null = null; // 需要改动的节点数组 shouldUpdate: boolean = false; From d1df21f26450b8cdd0a96f7351956ada41608038 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:42:16 +0800 Subject: [PATCH 14/35] Match-id-8100b99492d45f5c0d10ff72370a0fdc7ba249ad --- libs/horizon/src/dom/utils/DomCreator.ts | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/libs/horizon/src/dom/utils/DomCreator.ts b/libs/horizon/src/dom/utils/DomCreator.ts index 9d89ef5f..360aea81 100644 --- a/libs/horizon/src/dom/utils/DomCreator.ts +++ b/libs/horizon/src/dom/utils/DomCreator.ts @@ -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); } From 9a3c6440a13fbbe84660bfb7f89ca02a612029fd Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:47:15 +0800 Subject: [PATCH 15/35] Match-id-312daf8aa3b9932a2847f98e404ff35e5ea88b01 --- libs/horizon/src/renderer/TreeBuilder.ts | 4 ++-- libs/horizon/src/renderer/diff/nodeDiffComparator.ts | 10 +++++----- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 12 ++++-------- 3 files changed, 11 insertions(+), 15 deletions(-) diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 020b58b2..d6f852b4 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -18,7 +18,7 @@ import { setProcessingClassVNode, setStartVNode } from './GlobalVar'; -import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils'; +import { findDomParent } from './vnode/VNodeUtils'; import { ByAsync, BySync, @@ -108,7 +108,7 @@ function bubbleVNode(vNode: VNode): void { break; } - const siblingVNode = getSiblingVNode(node); + const siblingVNode = node.next; if (siblingVNode !== null) { // 有兄弟vNode processing = siblingVNode; return; diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index 0d65c816..dae6c74c 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -11,7 +11,7 @@ import { isIteratorType, isObjectType, } from './DiffTools'; -import {getSiblingVNode, travelChildren} from '../vnode/VNodeUtils'; +import { travelChildren } from '../vnode/VNodeUtils'; enum DiffCategory { TEXT_NODE = 'TEXT_NODE', @@ -249,7 +249,7 @@ function diffArrayNodes( nextOldNode = oldNode; oldNode = null; } else { - nextOldNode = getSiblingVNode(oldNode); + nextOldNode = oldNode.next; } const canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx]); @@ -552,13 +552,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; } } @@ -578,7 +578,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; } } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 82ad3ec8..78f18a50 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -8,10 +8,6 @@ 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; -} - export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) { let node: VNode | null = beginVNode; @@ -58,7 +54,7 @@ export function travelVNodeTree( } // 找兄弟,没有就往上再找兄弟 - while (getSiblingVNode(node) === null) { + while (node.next === null) { if (node.parent === null || node.parent === overVNode) { return null; } @@ -69,7 +65,7 @@ export function travelVNodeTree( } } // 找到兄弟 - const siblingVNode = getSiblingVNode(node); + const siblingVNode = node.next; siblingVNode.parent = node.parent; node = siblingVNode; } @@ -175,7 +171,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; @@ -183,7 +179,7 @@ export function getSiblingDom(vNode: VNode): Element | null { node = node.parent; } - const siblingVNode = getSiblingVNode(node); + const siblingVNode = node.next; siblingVNode.parent = node.parent; node = siblingVNode; From 3c1a4bc02af4c78b409ba150a5ddb0751496f928 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 11:58:28 +0800 Subject: [PATCH 16/35] Match-id-75b8c073cf610e8c3a74d1178c172caf13196702 --- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 8ce6d94b..66ee567f 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -65,7 +65,7 @@ export class VNode { clearChild: VNode | null = null; // one tree相关属性 isCreated: boolean = true; - oldHooks: Array> | null = []; // 保存上一次执行的hook + oldHooks: Array> | null = null; // 保存上一次执行的hook oldState: any = null; oldRef: RefType | ((handle: any) => void) | null = null; suspenseChildThrow = false; From fcd3a54a1a69afba7b1ab274fc1b836073b98406 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:09:07 +0800 Subject: [PATCH 17/35] Match-id-512f37017e5b961d1e1fda10ea7176284f4acaf7 --- libs/horizon/src/dom/DOMInternalKeys.ts | 26 +++++++++++-------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/libs/horizon/src/dom/DOMInternalKeys.ts b/libs/horizon/src/dom/DOMInternalKeys.ts index 6ddbdb5b..2f4ccb23 100644 --- a/libs/horizon/src/dom/DOMInternalKeys.ts +++ b/libs/horizon/src/dom/DOMInternalKeys.ts @@ -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 { - 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; } From c4c66b83f8951b13d95a12defc6a8b2cd2a47144 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:11:28 +0800 Subject: [PATCH 18/35] Match-id-8a1952b2ba54bca74a43f8772ace80b3908098d8 --- libs/horizon/src/dom/DOMOperator.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/horizon/src/dom/DOMOperator.ts b/libs/horizon/src/dom/DOMOperator.ts index 969219f0..9e61d65a 100644 --- a/libs/horizon/src/dom/DOMOperator.ts +++ b/libs/horizon/src/dom/DOMOperator.ts @@ -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'; From a6a992c192777cf3c7b174f1fc381347f3fabe09 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:12:13 +0800 Subject: [PATCH 19/35] Match-id-5991ef80bf0ba6d3c882eadd94851b9018e36f1b --- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 66ee567f..d349ead7 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -75,7 +75,7 @@ export class VNode { promiseResolve: boolean = false; // suspense的promise是否resolve path: string = ''; // 保存从根到本节点的路径 - toUpdateNodes: Set | null = null; // 保存要更新的节点 + toUpdateNodes: Set; // 保存要更新的节点 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 From b84d998fcb8977c4520933e87d383d9e56947fe3 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:24:13 +0800 Subject: [PATCH 20/35] Match-id-876a4a8b542f037d818e2b0d2eeb47f4b51faf1e --- .../DOMPropertiesHandler.ts | 74 +++++++++++-------- 1 file changed, 44 insertions(+), 30 deletions(-) diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts index 482a15a9..d0755511 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts @@ -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, 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({ From b8092c95cc0e0d7be11efaaf4ca8811722378ff7 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:27:09 +0800 Subject: [PATCH 21/35] Match-id-38d97bf1397ad5c12517c651a4455561a7112616 --- libs/horizon/src/dom/DOMOperator.ts | 2 +- libs/horizon/src/dom/DOMPropertiesHandler/UpdateCommonProp.ts | 2 +- libs/horizon/src/dom/valueHandler/InputValueHandler.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libs/horizon/src/dom/DOMOperator.ts b/libs/horizon/src/dom/DOMOperator.ts index 9e61d65a..169e85b2 100644 --- a/libs/horizon/src/dom/DOMOperator.ts +++ b/libs/horizon/src/dom/DOMOperator.ts @@ -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); diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/UpdateCommonProp.ts b/libs/horizon/src/dom/DOMPropertiesHandler/UpdateCommonProp.ts index 5af59913..468408ac 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/UpdateCommonProp.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/UpdateCommonProp.ts @@ -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)) { diff --git a/libs/horizon/src/dom/valueHandler/InputValueHandler.ts b/libs/horizon/src/dom/valueHandler/InputValueHandler.ts index e081a5ea..368bf288 100644 --- a/libs/horizon/src/dom/valueHandler/InputValueHandler.ts +++ b/libs/horizon/src/dom/valueHandler/InputValueHandler.ts @@ -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); } } From 6f977fce7af360c78c56de0bd0fd9e57f09d5c54 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:31:45 +0800 Subject: [PATCH 22/35] Match-id-c9903f0cf11854c6f9df9974b95a3a1b2c534371 --- libs/horizon/src/renderer/ContextSaver.ts | 27 ++++++++++++++--------- libs/horizon/src/renderer/vnode/VNode.ts | 7 ------ 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/libs/horizon/src/renderer/ContextSaver.ts b/libs/horizon/src/renderer/ContextSaver.ts index d092dd76..05847b08 100644 --- a/libs/horizon/src/renderer/ContextSaver.ts +++ b/libs/horizon/src/renderer/ContextSaver.ts @@ -29,17 +29,24 @@ let ctxOldContext: Object = {}; let ctxOldChange: Boolean = false; let ctxOldPreviousContext: Object = {}; +function setContext(vNode: VNode, contextName, value) { + vNode.contexts[contextName] = value; +} +function getContext(vNode: VNode, contextName) { + 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 +56,14 @@ function getNamespaceCtx(): string { function setContextCtx(providerVNode: VNode, nextValue: T) { const context: ContextType = 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 = providerVNode.type._context; - context.value = providerVNode.getContext(CTX_CONTEXT); + context.value = getContext(providerVNode, CTX_CONTEXT); } // 在局部更新时,恢复父节点的context @@ -74,11 +81,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 +102,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 +118,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 +127,7 @@ function getContextChangeCtx() { } function resetContextChangeCtx(vNode: VNode) { - ctxOldChange = vNode.getContext(CTX_OLD_CHANGE); + ctxOldChange = getContext(vNode, CTX_OLD_CHANGE); } export { diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index d349ead7..0562b7d2 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -92,11 +92,4 @@ export class VNode { this.toUpdateNodes = new Set(); } } - - setContext(contextName, value) { - this.contexts[contextName] = value; - } - getContext(contextName) { - return this.contexts[contextName]; - } } From 0ff6a0bddb616d7373b670b6f481b7210ea6cea5 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:35:14 +0800 Subject: [PATCH 23/35] Match-id-be8ec88f391f0dff5b761a62104e86f07dee1a42 --- libs/horizon/src/renderer/diff/DiffTools.ts | 4 ---- libs/horizon/src/renderer/diff/nodeDiffComparator.ts | 9 ++++----- 2 files changed, 4 insertions(+), 9 deletions(-) diff --git a/libs/horizon/src/renderer/diff/DiffTools.ts b/libs/horizon/src/renderer/diff/DiffTools.ts index 9b152d92..42fd2864 100644 --- a/libs/horizon/src/renderer/diff/DiffTools.ts +++ b/libs/horizon/src/renderer/diff/DiffTools.ts @@ -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']; } diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index dae6c74c..a807b73a 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -7,7 +7,6 @@ import { isSameType, getIteratorFn, isTextType, - isArrayType, isIteratorType, isObjectType, } from './DiffTools'; @@ -60,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) { @@ -79,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) { @@ -200,7 +199,7 @@ function getOldNodeFromMap(nodeMap: Map, 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) { @@ -629,7 +628,7 @@ export function createChildrenByDiff( } // 3. newChild是数组类型 - if (isArrayType(newChild)) { + if (Array.isArray(newChild)) { return diffArrayNodesHandler(parentNode, firstChild, newChild, isComparing); } From b55ab599b20345143e3fad0d8ce6b7c43aae5838 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:42:42 +0800 Subject: [PATCH 24/35] Match-id-816ac7b4af214e4dae368f74f23df0b478d2c62f --- .../src/renderer/diff/nodeDiffComparator.ts | 39 ++++++++----------- 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index a807b73a..530e9f87 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -215,11 +215,11 @@ function setCIndex(vNode: VNode, idx: number) { } // diff数组类型的节点,核心算法 -function diffArrayNodes( +function diffArrayNodesHandler( parentNode: VNode, firstChild: VNode | null, newChildren: Array, - isComparing: boolean = true + isComparing: boolean ): VNode | null { let resultingFirstChild: VNode | null = null; @@ -241,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) { @@ -251,14 +253,14 @@ function diffArrayNodes( 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; @@ -286,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; @@ -345,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); @@ -371,9 +374,11 @@ function diffArrayNodes( const preIndex: Array = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录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 @@ -383,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); @@ -461,16 +466,6 @@ function setVNodesCIndex(startChild: VNode, startIdx: number) { } } -// 新节点是数组类型 -function diffArrayNodesHandler( - parentNode: VNode, - firstChild: VNode | null, - newChildren: Array, - isComparing: boolean = true -): VNode | null { - return diffArrayNodes(parentNode, firstChild, newChildren, isComparing); -} - // 新节点是迭代器类型 function diffIteratorNodesHandler( parentNode: VNode, @@ -489,7 +484,7 @@ function diffIteratorNodesHandler( result = iteratorObj.next(); } - return diffArrayNodes(parentNode, firstChild, childrenArray, isComparing); + return diffArrayNodesHandler(parentNode, firstChild, childrenArray, isComparing); } // 新节点是字符串类型 From 08295b4fb45865aa54c3dde859a526147ae48a55 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:44:06 +0800 Subject: [PATCH 25/35] Match-id-9301db1f5ae58c6e7f046efc003b8dff452d0a82 --- libs/horizon/src/renderer/render/BaseComponent.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts index 8e5e56d4..1b2edf2d 100644 --- a/libs/horizon/src/renderer/render/BaseComponent.ts +++ b/libs/horizon/src/renderer/render/BaseComponent.ts @@ -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) { From 832a5b51c2630ac742b493e5d17ac181466f2b0e Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:46:23 +0800 Subject: [PATCH 26/35] Match-id-0c37ff516aeaae15ec0f4882fd289389ace4455b --- .../src/renderer/render/DomComponent.ts | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index bac845b1..fff571a6 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -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; From 74c1452b078f9fa9f0304ed7f974acb47a7c706a Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 14:58:30 +0800 Subject: [PATCH 27/35] Match-id-b5f917c72588dc46381019cba0455e0369de6e5b --- libs/horizon/src/renderer/ContextSaver.ts | 12 ++++++-- .../src/renderer/render/DomComponent.ts | 30 +++++++++---------- libs/horizon/src/renderer/vnode/VNode.ts | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/libs/horizon/src/renderer/ContextSaver.ts b/libs/horizon/src/renderer/ContextSaver.ts index 05847b08..62586895 100644 --- a/libs/horizon/src/renderer/ContextSaver.ts +++ b/libs/horizon/src/renderer/ContextSaver.ts @@ -30,10 +30,18 @@ let ctxOldChange: Boolean = false; let ctxOldPreviousContext: Object = {}; function setContext(vNode: VNode, contextName, value) { - vNode.contexts[contextName] = value; + if (vNode.contexts === null) { + vNode.contexts = { + [contextName]: value, + }; + } else { + vNode.contexts[contextName] = value; + } } function getContext(vNode: VNode, contextName) { - return vNode.contexts[contextName]; + if (vNode.contexts !== null) { + return vNode.contexts[contextName]; + } } // capture阶段设置 diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index fff571a6..7aef0d8d 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -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, @@ -80,15 +80,15 @@ export function bubbleRender(processing: VNode) { // 把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); + // 向下递归它的子节点,查找所有终端节点。 + 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; diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 0562b7d2..1160681a 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -42,7 +42,7 @@ export class VNode { task: any; // 使用这个变量来记录修改前的值,用于恢复。 - contexts = {}; + contexts: any = null; // 因为LazyComponent会修改tag和type属性,为了能识别,增加一个属性 isLazyComponent: boolean = false; From f46c73cc6c31802ea6209fb17db567ea4106ce54 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 17:05:45 +0800 Subject: [PATCH 28/35] Match-id-734c7025e4bf66d1c909d3f3e46d57554e02aeb1 --- libs/horizon/src/renderer/vnode/VNode.ts | 131 +++++++++++++----- .../src/renderer/vnode/VNodeCreator.ts | 3 +- 2 files changed, 101 insertions(+), 33 deletions(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 1160681a..9f9a66c0 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -1,16 +1,17 @@ /** * 虚拟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'; export class VNode { tag: VNodeTag; key: string | null; // 唯一标识符 + props: any; // 传给组件的props的值,类组件包含defaultProps,Lazy组件不包含 type: any = null; - realNode: any = null; // 如果是类,则存放实例;如果是div这种,则存放真实DOM; + realNode: any; // 如果是类,则存放实例;如果是div这种,则存放真实DOM; // 关系结构 parent: VNode | null = null; // 父节点 @@ -20,21 +21,20 @@ 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的值,类组件包含defaultProps,Lazy组件不包含 oldProps: any = null; - suspensePromises: any = null; // suspense组件的promise列表 - changeList: any = null; // DOM的变更列表 - effectList: any[] | null = null; // useEffect 的更新数组 - updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组 - stateCallbacks: any[] | null = null; // 存放存在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> | null = null; // 保存hook + state: any; // ClassComponent和TreeRoot的状态 + hooks: Array> | null; // 保存hook suspenseChildStatus: string = ''; // Suspense的Children是否显示 - depContexts: Array> | null = null; // FunctionComponent和ClassComponent对context的依赖列表 - isDepContextChange: boolean = false; // context是否变更 + depContexts: Array> | null; // FunctionComponent和ClassComponent对context的依赖列表 + isDepContextChange: boolean; // context是否变更 dirtyNodes: Array | null = null; // 需要改动的节点数组 shouldUpdate: boolean = false; childShouldUpdate: boolean = false; @@ -42,12 +42,12 @@ export class VNode { task: any; // 使用这个变量来记录修改前的值,用于恢复。 - contexts: any = null; + contexts: any; // 因为LazyComponent会修改tag和type属性,为了能识别,增加一个属性 - isLazyComponent: boolean = false; + isLazyComponent: boolean; // 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType - lazyType: any = null; + lazyType: any; flags: { Addition?: boolean; Update?: boolean; @@ -62,17 +62,17 @@ export class VNode { ForceUpdate?: boolean; Clear?: boolean; } = {}; - clearChild: VNode | null = null; + clearChild: VNode | null; // one tree相关属性 isCreated: boolean = true; - oldHooks: Array> | null = null; // 保存上一次执行的hook - oldState: any = null; + oldHooks: Array> | 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: string = ''; // 保存从根到本节点的路径 toUpdateNodes: Set; // 保存要更新的节点 @@ -85,11 +85,80 @@ export class VNode { this.props = props; - // 根节点 - if (tag === TreeRoot) { - this.outerDom = outerDom; - this.task = null; - this.toUpdateNodes = new Set(); + switch (tag) { + case TreeRoot: + this.outerDom = outerDom; + this.task = null; + this.toUpdateNodes = new Set(); + 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; } } } diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 2d6d3bb2..ca585e5f 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -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; From b0c3086a774b54e0ac52bb43471743f6ce9a31a6 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 19:27:00 +0800 Subject: [PATCH 29/35] Match-id-97a6395f2682889472335c90b2a743d288f37fcc --- libs/horizon/src/renderer/ErrorHandler.ts | 4 +- libs/horizon/src/renderer/TreeBuilder.ts | 6 +- .../src/renderer/render/ClassComponent.ts | 8 +- .../src/renderer/submit/LifeCycleHandler.ts | 8 +- libs/horizon/src/renderer/submit/Submit.ts | 33 +++---- libs/horizon/src/renderer/vnode/VNode.ts | 18 +--- libs/horizon/src/renderer/vnode/VNodeFlags.ts | 90 ++++++++----------- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 6 +- 8 files changed, 73 insertions(+), 100 deletions(-) diff --git a/libs/horizon/src/renderer/ErrorHandler.ts b/libs/horizon/src/renderer/ErrorHandler.ts index 991ef861..837f25c5 100644 --- a/libs/horizon/src/renderer/ErrorHandler.ts +++ b/libs/horizon/src/renderer/ErrorHandler.ts @@ -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'; @@ -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') diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index d6f852b4..0f13627d 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -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'; @@ -86,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); } } diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index b459215c..9c4c1f20 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -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 diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 354a179e..55edf2c7 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -17,7 +17,7 @@ import { SuspenseComponent, MemoComponent, } from '../vnode/VNodeTags'; -import { FlagUtils, ResetText, Clear } from '../vnode/VNodeFlags'; +import { FlagUtils, ResetText, Clear, Update } from '../vnode/VNodeFlags'; import { mergeDefaultProps } from '../render/LazyComponent'; import { submitDomUpdate, @@ -97,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 { @@ -124,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(); @@ -222,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); diff --git a/libs/horizon/src/renderer/submit/Submit.ts b/libs/horizon/src/renderer/submit/Submit.ts index 30fee9d8..ae4027f3 100644 --- a/libs/horizon/src/renderer/submit/Submit.ts +++ b/libs/horizon/src/renderer/submit/Submit.ts @@ -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 { @@ -91,7 +89,7 @@ export function submitToRender(treeRoot) { function beforeSubmit(dirtyNodes: Array) { dirtyNodes.forEach(node => { try { - if (node.flags.Snapshot) { + if ((node.flags & Snapshot) === Snapshot) { callBeforeSubmitLifeCycles(node); } } catch (error) { @@ -103,35 +101,38 @@ function beforeSubmit(dirtyNodes: Array) { function submit(dirtyNodes: Array) { 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); } } @@ -144,11 +145,11 @@ function submit(dirtyNodes: Array) { function afterSubmit(dirtyNodes: Array) { 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) { diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 9f9a66c0..5799e34c 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -5,6 +5,7 @@ import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, Contex 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; @@ -48,20 +49,7 @@ export class VNode { // 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType lazyType: any; - 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; - } = {}; + flags = InitFlag; clearChild: VNode | null; // one tree相关属性 isCreated: boolean = true; @@ -75,7 +63,7 @@ export class VNode { promiseResolve: boolean; // suspense的promise是否resolve path: string = ''; // 保存从根到本节点的路径 - toUpdateNodes: Set; // 保存要更新的节点 + toUpdateNodes: Set | null; // 保存要更新的节点 belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts index 48d0331d..62f98803 100644 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts @@ -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; } } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index 78f18a50..c9d4b572 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -7,6 +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'; +import { Addition, InitFlag } from './VNodeFlags'; export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) { let node: VNode | null = beginVNode; @@ -92,6 +93,7 @@ export function clearVNode(vNode: VNode) { vNode.oldState = null; vNode.oldRef = null; vNode.oldChild = null; + vNode.flags = InitFlag; vNode.toUpdateNodes = null; @@ -186,7 +188,7 @@ export function getSiblingDom(vNode: VNode): Element | null { // 如果不是dom节点,往下找 while (!isDomVNode(node)) { // 如果节点也是Addition - if (node.flags.Addition) { + if ((node.flags & Addition) ===Addition) { continue findSibling; } @@ -200,7 +202,7 @@ export function getSiblingDom(vNode: VNode): Element | null { } } - if (!node.flags.Addition) { + if ((node.flags & Addition) ===InitFlag) { // 找到 return node.realNode; } From 3a242e79213bad735dd18b5d39e9c706bc115587 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 20:20:38 +0800 Subject: [PATCH 30/35] Match-id-f9204abb03ec4372ff212799440e0c744b176e36 --- libs/horizon/src/renderer/TreeBuilder.ts | 23 +++++--- .../src/renderer/submit/LifeCycleHandler.ts | 52 ++++++++++++++++--- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 18 ------- 3 files changed, 59 insertions(+), 34 deletions(-) diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 0f13627d..76de8ae4 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -2,7 +2,7 @@ import type { VNode } from './Types'; import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue'; import { updateVNode } from './vnode/VNodeCreator'; -import { TreeRoot } from './vnode/VNodeTags'; +import { TreeRoot, DomComponent, DomPortal } from './vnode/VNodeTags'; import { FlagUtils, InitFlag, Interrupted } from './vnode/VNodeFlags'; import { captureVNode } from './render/BaseComponent'; import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit'; @@ -18,7 +18,6 @@ import { setProcessingClassVNode, setStartVNode } from './GlobalVar'; -import { findDomParent } from './vnode/VNodeUtils'; import { ByAsync, BySync, @@ -223,13 +222,21 @@ function buildVNodeTree(treeRoot: VNode) { if (startVNode.tag !== TreeRoot) { // 不是根节点 // 设置namespace,用于createElement - const parentObj = findDomParent(startVNode); - + let parent = startVNode.parent; + while (parent !== null) { + const tag = parent.tag; + if (tag === DomComponent) { + break; + } else if (tag === TreeRoot || tag === DomPortal) { + break; + } + parent = parent.parent; + } + // 当在componentWillUnmount中调用setState,parent可能是null,因为startVNode会被clear - if (parentObj !== null) { - const domParent = parentObj.parent; - resetNamespaceCtx(domParent); - setNamespaceCtx(domParent, domParent.outerDom); + if (parent !== null) { + resetNamespaceCtx(parent); + setNamespaceCtx(parent, parent.outerDom); } // 恢复父节点的context diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 55edf2c7..a9d8344d 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -39,7 +39,7 @@ import { travelVNodeTree, clearVNode, isDomVNode, - findDomParent, getSiblingDom, + getSiblingDom, } from '../vnode/VNodeUtils'; import { shouldAutoFocus } from '../../dom/utils/Common'; @@ -220,7 +220,20 @@ function unmountNestedVNodes(vNode: VNode): void { } function submitAddition(vNode: VNode): void { - const { parent, parentDom } = findDomParent(vNode); + let parent = vNode.parent; + let parentDom; + let tag; + while (parent !== null) { + tag = parent.tag; + if (tag === DomComponent) { + parentDom = parent.realNode; + break; + } else if (tag === TreeRoot || tag === DomPortal) { + parentDom = parent.outerDom; + break; + } + parent = parent.parent; + } if ((vNode.flags & ResetText) === ResetText) { // 在insert之前先reset @@ -270,8 +283,19 @@ function unmountDomComponents(vNode: VNode): void { travelVNodeTree(vNode, (node) => { if (!currentParentIsValid) { - const parentObj = findDomParent(node); - currentParent = parentObj.parentDom; + let parent = node.parent; + let tag; + while (parent !== null) { + tag = parent.tag; + if (tag === DomComponent) { + currentParent = parent.realNode; + break; + } else if (tag === TreeRoot || tag === DomPortal) { + currentParent = parent.outerDom; + break; + } + parent = parent.parent; + } currentParentIsValid = true; } @@ -315,8 +339,20 @@ function submitClear(vNode: VNode): void { } } - const parentObj = findDomParent(vNode); - const currentParent = parentObj.parentDom; + let parent = vNode.parent; + let parentDom; + let tag; + while (parent !== null) { + tag = parent.tag; + if (tag === DomComponent) { + parentDom = parent.realNode; + break; + } else if (tag === TreeRoot || tag === DomPortal) { + parentDom = parent.outerDom; + break; + } + parent = parent.parent; + } let clearChild = vNode.clearChild as VNode; // 上次渲染的child保存在clearChild属性中 // 卸载 clearChild 和 它的兄弟节点 while(clearChild) { @@ -327,9 +363,9 @@ function submitClear(vNode: VNode): void { } // 在所有子项都卸载后,删除dom树中的节点 - removeChildDom(currentParent, vNode.realNode); + removeChildDom(parentDom, vNode.realNode); const realNodeNext = getSiblingDom(vNode); - insertDom(currentParent, cloneDom, realNodeNext); + insertDom(parentDom, cloneDom, realNodeNext); vNode.realNode = cloneDom; attachRef(vNode); FlagUtils.removeFlag(vNode, Clear); diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index c9d4b572..cc56591c 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -114,24 +114,6 @@ function isDomContainer(vNode: VNode): boolean { ); } -// 找到DOM类型的父 -export function findDomParent(vNode: VNode) { - let parent = vNode.parent; - - while (parent !== null) { - switch (parent.tag) { - case DomComponent: - return {parent, parentDom: parent.realNode}; - case TreeRoot: - case DomPortal: - return {parent, parentDom: parent.outerDom}; - } - parent = parent.parent; - } - - return null; -} - export function findDomVNode(vNode: VNode): VNode | null { return travelVNodeTree(vNode, (node) => { if (node.tag === DomComponent || node.tag === DomText) { From 91dc5656ab8228143167e97154b71b6124d873e0 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 20:22:10 +0800 Subject: [PATCH 31/35] Match-id-c74211ebd4670fd9c8b20892189f91fb10bce812 --- libs/horizon/src/event/EventBinding.ts | 4 +- libs/horizon/src/event/HorizonEventMain.ts | 20 ++---- libs/horizon/src/event/ListenerGetter.ts | 9 ++- libs/horizon/src/event/Types.ts | 3 +- libs/horizon/src/event/const.ts | 3 + .../src/event/customEvents/CustomBaseEvent.ts | 70 ------------------- .../src/event/customEvents/EventFactory.ts | 38 +++++++--- .../BeforeInputEventHandler.ts | 6 +- .../CompositionEventHandler.ts | 30 -------- .../SelectionEventHandler.ts | 8 +-- libs/horizon/src/event/utils.ts | 7 ++ 11 files changed, 58 insertions(+), 140 deletions(-) delete mode 100644 libs/horizon/src/event/customEvents/CustomBaseEvent.ts delete mode 100644 libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts diff --git a/libs/horizon/src/event/EventBinding.ts b/libs/horizon/src/event/EventBinding.ts index 512e87b5..54d3fdb4 100644 --- a/libs/horizon/src/event/EventBinding.ts +++ b/libs/horizon/src/event/EventBinding.ts @@ -7,11 +7,11 @@ import { getNearestVNode, getNonDelegatedListenerMap, } from '../dom/DOMInternalKeys'; -import {CustomBaseEvent} from './customEvents/CustomBaseEvent'; import {runDiscreteUpdates} from '../renderer/TreeBuilder'; import {isMounted} from '../renderer/vnode/VNodeUtils'; import {SuspenseComponent} from '../renderer/vnode/VNodeTags'; import {handleEventMain} from './HorizonEventMain'; +import {decorateNativeEvent} from './customEvents/EventFactory'; const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4); @@ -98,7 +98,7 @@ function isCaptureEvent(horizonEventName) { // 封装监听函数 function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) { return event => { - const customEvent = new CustomBaseEvent(horizonEventName, nativeEvtName, event, null, targetElement); + const customEvent = decorateNativeEvent(horizonEventName, nativeEvtName, event); listener(customEvent); }; } diff --git a/libs/horizon/src/event/HorizonEventMain.ts b/libs/horizon/src/event/HorizonEventMain.ts index deabece1..e099dda8 100644 --- a/libs/horizon/src/event/HorizonEventMain.ts +++ b/libs/horizon/src/event/HorizonEventMain.ts @@ -8,13 +8,12 @@ import { EVENT_TYPE_CAPTURE, } from './const'; import { getListeners as getBeforeInputListeners } from './simulatedEvtHandler/BeforeInputEventHandler'; -import { getListeners as getCompositionListeners } from './simulatedEvtHandler/CompositionEventHandler'; import { getListeners as getChangeListeners } from './simulatedEvtHandler/ChangeEventHandler'; import { getListeners as getSelectionListeners } from './simulatedEvtHandler/SelectionEventHandler'; import { - addOnPrefix, + addOnPrefix, setPropertyWritable, } from './utils'; -import { createCustomEvent } from './customEvents/EventFactory'; +import { decorateNativeEvent } from './customEvents/EventFactory'; import { getListenersFromTree } from './ListenerGetter'; import { shouldUpdateValue, updateControlledValue } from './ControlledValueUpdater'; import { asyncUpdates, runDiscreteUpdates } from '../renderer/Renderer'; @@ -47,7 +46,7 @@ function getCommonListeners( nativeEvtName = 'blur'; } - const horizonEvent = createCustomEvent(horizonEvtName, nativeEvtName, nativeEvent, target); + const horizonEvent = decorateNativeEvent(horizonEvtName, nativeEvtName, nativeEvent); return getListenersFromTree( vNode, horizonEvtName, @@ -63,6 +62,8 @@ function processListeners(listenerList: ListenerUnitList): void { if (event.isPropagationStopped()) { return; } + + setPropertyWritable(event, 'currentTarget'); event.currentTarget = currentTarget; listener(event); event.currentTarget = null; @@ -105,17 +106,6 @@ function getProcessListeners( )); } - if (nativeEvtName === 'compositionend' || - nativeEvtName === 'compositionstart' || - nativeEvtName === 'compositionupdate') { - listenerList = listenerList.concat(getCompositionListeners( - nativeEvtName, - nativeEvent, - vNode, - target, - )); - } - if (horizonEventToNativeMap.get('onBeforeInput').includes(nativeEvtName)) { listenerList = listenerList.concat(getBeforeInputListeners( nativeEvtName, diff --git a/libs/horizon/src/event/ListenerGetter.ts b/libs/horizon/src/event/ListenerGetter.ts index 8c20b960..53e14ee9 100644 --- a/libs/horizon/src/event/ListenerGetter.ts +++ b/libs/horizon/src/event/ListenerGetter.ts @@ -1,14 +1,13 @@ import {VNode} from '../renderer/Types'; import {DomComponent} from '../renderer/vnode/VNodeTags'; import {EVENT_TYPE_ALL, EVENT_TYPE_CAPTURE, EVENT_TYPE_BUBBLE} from './const'; -import {ListenerUnitList} from './Types'; -import {CustomBaseEvent} from './customEvents/CustomBaseEvent'; +import {AnyNativeEvent, ListenerUnitList} from './Types'; // 获取监听事件 export function getListenersFromTree( targetVNode: VNode | null, horizonEvtName: string | null, - horizonEvent: CustomBaseEvent, + nativeEvent: AnyNativeEvent, eventType: string, ): ListenerUnitList { if (!horizonEvtName) { @@ -31,7 +30,7 @@ export function getListenersFromTree( vNode, listener: captureListener, currentTarget: realNode, - event: horizonEvent, + event: nativeEvent, }); } } @@ -43,7 +42,7 @@ export function getListenersFromTree( vNode, listener: bubbleListener, currentTarget: realNode, - event: horizonEvent, + event: nativeEvent, }); } } diff --git a/libs/horizon/src/event/Types.ts b/libs/horizon/src/event/Types.ts index b007bb2c..12071e36 100644 --- a/libs/horizon/src/event/Types.ts +++ b/libs/horizon/src/event/Types.ts @@ -1,6 +1,5 @@ import type {VNode} from '../renderer/Types'; -import {CustomBaseEvent} from './customEvents/CustomBaseEvent'; export type AnyNativeEvent = KeyboardEvent | MouseEvent | TouchEvent | UIEvent | Event; @@ -8,7 +7,7 @@ export type ListenerUnit = { vNode: null | VNode; listener: Function; currentTarget: EventTarget; - event: CustomBaseEvent; + event: AnyNativeEvent; }; export type ListenerUnitList = Array; diff --git a/libs/horizon/src/event/const.ts b/libs/horizon/src/event/const.ts index a3c2805e..7aebfa15 100644 --- a/libs/horizon/src/event/const.ts +++ b/libs/horizon/src/event/const.ts @@ -66,6 +66,9 @@ export const CommonEventToHorizonMap = { animationiteration: 'animationIteration', animationstart: 'animationStart', transitionend: 'transitionEnd', + compositionstart: 'compositionStart', + compositionend: 'compositionEnd', + compositionupdate: 'compositionUpdate', }; export const CHAR_CODE_ENTER = 13; diff --git a/libs/horizon/src/event/customEvents/CustomBaseEvent.ts b/libs/horizon/src/event/customEvents/CustomBaseEvent.ts deleted file mode 100644 index 299a754d..00000000 --- a/libs/horizon/src/event/customEvents/CustomBaseEvent.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 自定义的基本事件类型 - */ - -// 兼容IE的event key -const uniqueKeyMap = new Map([ - ['Esc', 'Escape'], - ['Spacebar', ' '], - ['Left', 'ArrowLeft'], - ['Up', 'ArrowUp'], - ['Right', 'ArrowRight'], - ['Down', 'ArrowDown'], - ['Del', 'Delete'], -]); - -// 从原生事件中复制属性到自定义事件中 -function extendAttribute(target, source) { - let val; - let attr; - for (attr in source) { - val = source[attr]; - if (val !== undefined) { - if (typeof val === 'function') { - let fun = source[attr]; - target[attr] = function() { - return fun.apply(source, arguments); - }; - } else { - target[attr] = val; - } - } - } -} - -export class CustomBaseEvent { - - isDefaultPrevented: () => boolean; - isPropagationStopped: () => boolean; - target: EventTarget | null; - - // 键盘事件属性 - key: string; - - // custom事件自定义属性 - customEventName: string; - type: string; - nativeEvent: any; - - constructor( - customEvtName: string, - nativeEvtName: string, - nativeEvt: { [propName: string]: any }, - target: EventTarget | null - ) { - // 复制原生属性到自定义事件 - extendAttribute(this, nativeEvt); - - this.isDefaultPrevented = () => nativeEvt.defaultPrevented; - this.isPropagationStopped = () => nativeEvt.cancelBubble; - this.target = target; - - // 键盘事件属性 - this.key = uniqueKeyMap.get(nativeEvt.key) || nativeEvt.key; - - // custom事件自定义属性 - this.customEventName = customEvtName; - this.type = nativeEvtName; - this.nativeEvent = nativeEvt; - } -} diff --git a/libs/horizon/src/event/customEvents/EventFactory.ts b/libs/horizon/src/event/customEvents/EventFactory.ts index c92a8aaa..db6bfc17 100644 --- a/libs/horizon/src/event/customEvents/EventFactory.ts +++ b/libs/horizon/src/event/customEvents/EventFactory.ts @@ -1,11 +1,33 @@ -import {CustomBaseEvent} from './CustomBaseEvent'; + +// 兼容IE的event key +const uniqueKeyMap = new Map([ + ['Esc', 'Escape'], + ['Spacebar', ' '], + ['Left', 'ArrowLeft'], + ['Up', 'ArrowUp'], + ['Right', 'ArrowRight'], + ['Down', 'ArrowDown'], + ['Del', 'Delete'], +]); // 创建普通自定义事件对象实例,和原生事件对应 -export function createCustomEvent(customEventName, nativeEvtName, nativeEvent, currentTarget) { - return new CustomBaseEvent( - customEventName, - nativeEvtName, - nativeEvent, - currentTarget, - ); +export function decorateNativeEvent(customEventName, nativeEvtName, nativeEvent) { + + nativeEvent.isDefaultPrevented = () => nativeEvent.defaultPrevented; + nativeEvent.isPropagationStopped = () => nativeEvent.cancelBubble; + + // custom事件自定义属性 + nativeEvent.customEventName = customEventName; + nativeEvent.nativeEvent = nativeEvent; + // 保存原生的事件类型,因为下面会修改 + nativeEvent.nativeEventType = nativeEvent.type; + + Object.defineProperty(nativeEvent, 'type', { writable: true }); + nativeEvent.type = nativeEvtName; + + const orgKey = nativeEvent.key; + Object.defineProperty(nativeEvent, 'key', { writable: true }); + nativeEvent.key = uniqueKeyMap.get(orgKey) || orgKey; + + return nativeEvent; } diff --git a/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts index 3d26a9a4..e05b175f 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/BeforeInputEventHandler.ts @@ -1,9 +1,8 @@ import type {VNode} from '../../renderer/Types'; import type {AnyNativeEvent} from '../Types'; import {getListenersFromTree} from '../ListenerGetter'; -import {createCustomEvent} from '../customEvents/EventFactory'; +import {decorateNativeEvent} from '../customEvents/EventFactory'; import {CHAR_CODE_SPACE, EVENT_TYPE_ALL} from '../const'; -import {CustomBaseEvent} from '../customEvents/CustomBaseEvent'; import {ListenerUnitList} from '../Types'; const SPACE_CHAR = String.fromCharCode(CHAR_CODE_SPACE); @@ -36,11 +35,10 @@ export function getListeners( return []; } - const event: CustomBaseEvent = createCustomEvent( + const event: AnyNativeEvent = decorateNativeEvent( 'onBeforeInput', 'beforeinput', nativeEvent, - target, ); event.data = chars; diff --git a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts deleted file mode 100644 index 9dd8731c..00000000 --- a/libs/horizon/src/event/simulatedEvtHandler/CompositionEventHandler.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type {VNode} from '../../renderer/Types'; -import type {AnyNativeEvent} from '../Types'; -import {getListenersFromTree} from '../ListenerGetter'; -import {createCustomEvent} from '../customEvents/EventFactory'; -import {EVENT_TYPE_ALL} from '../const'; -import {ListenerUnitList} from '../Types'; - -const compositionEventObj = { - compositionstart: 'onCompositionStart', - compositionend: 'onCompositionEnd', - compositionupdate: 'onCompositionUpdate', -}; - -// compoisition事件主要处理中文输入法输入时的触发事件 -export function getListeners( - nativeEvtName: string, - nativeEvt: AnyNativeEvent, - vNode: null | VNode, - target: null | EventTarget, -): ListenerUnitList { - const evtType = compositionEventObj[nativeEvtName]; - - const event = createCustomEvent( - evtType, - nativeEvtName, - nativeEvt, - target, - ); - return getListenersFromTree(vNode, evtType, event, EVENT_TYPE_ALL); -} diff --git a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts index 778a3b82..cd5a09ad 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/SelectionEventHandler.ts @@ -1,9 +1,9 @@ -import {createCustomEvent} from '../customEvents/EventFactory'; +import {decorateNativeEvent} from '../customEvents/EventFactory'; import {shallowCompare} from '../../renderer/utils/compare'; import {getFocusedDom} from '../../dom/utils/Common'; import {getDom} from '../../dom/DOMInternalKeys'; import {isDocument} from '../../dom/utils/Common'; -import {isInputElement} from '../utils'; +import {isInputElement, setPropertyWritable} from '../utils'; import type {AnyNativeEvent} from '../Types'; import {getListenersFromTree} from '../ListenerGetter'; import type {VNode} from '../../renderer/Types'; @@ -54,12 +54,12 @@ function getSelectEvent(nativeEvent, target) { if (!shallowCompare(lastSelection, currentSelection)) { lastSelection = currentSelection; - const event = createCustomEvent( + const event = decorateNativeEvent( horizonEventName, 'select', nativeEvent, - target, ); + setPropertyWritable(nativeEvent, 'target'); event.target = currentElement; return getListenersFromTree( diff --git a/libs/horizon/src/event/utils.ts b/libs/horizon/src/event/utils.ts index 3909e7a8..d4b6f143 100644 --- a/libs/horizon/src/event/utils.ts +++ b/libs/horizon/src/event/utils.ts @@ -14,3 +14,10 @@ export function addOnPrefix(name) { } return 'on' + name[0].toUpperCase() + name.slice(1); } + +export function setPropertyWritable(obj, propName) { + const desc = Object.getOwnPropertyDescriptor(obj, propName); + if (!desc || !desc.writable) { + Object.defineProperty(obj, propName, { writable : true }); + } +} From 24d53da4d615be9609732d30e073f4587cea4d53 Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 20:23:48 +0800 Subject: [PATCH 32/35] Match-id-706e1c5d83ec5e03eb89bbbe0d2be5fd18b586e1 --- libs/horizon/src/renderer/vnode/VNode.ts | 1 + libs/horizon/src/renderer/vnode/VNodeCreator.ts | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 5799e34c..371e488d 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -136,6 +136,7 @@ export class VNode { case LazyComponent: this.realNode = null; this.stateCallbacks = null; + this.isLazyComponent = true; break; case Fragment: break; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index ca585e5f..c8832fa8 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -134,7 +134,6 @@ export function createUndeterminedVNode(type, key, props) { vNode.shouldUpdate = true; if (isLazy) { - vNode.isLazyComponent = isLazy; vNode.lazyType = type; } return vNode; From bd7c640db67ef5a1fcbc09764891a2ca33cd52bf Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 20:29:51 +0800 Subject: [PATCH 33/35] Match-id-9ccbe249bd64aa265df986ea76dfa1446be57717 --- libs/horizon/src/renderer/vnode/VNode.ts | 1 + .../src/renderer/vnode/VNodeCreator.ts | 41 ++++++++----------- 2 files changed, 19 insertions(+), 23 deletions(-) diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 371e488d..a48c4ab9 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -137,6 +137,7 @@ export class VNode { this.realNode = null; this.stateCallbacks = null; this.isLazyComponent = true; + this.lazyType = null; break; case Fragment: break; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index c8832fa8..b37fa3c7 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -84,28 +84,6 @@ export function updateVNode(vNode: VNode, vNodeProps?: any): VNode { return vNode; } -function getVNodeTag(type: any) { - let vNodeTag = ClsOrFunComponent; - let isLazy = false; - const componentType = typeof type; - - if (componentType === 'function') { - if (isClassComponent(type)) { - vNodeTag = ClassComponent; - } - } else if (componentType === 'string') { - vNodeTag = DomComponent; - } else if (type === TYPE_SUSPENSE) { - vNodeTag = SuspenseComponent; - } else if (componentType === 'object' && type !== null && typeMap[type.vtype]) { - vNodeTag = typeMap[type.vtype]; - isLazy = type.vtype === TYPE_LAZY; - } else { - throw Error(`Component type is invalid, got: ${type == null ? type : componentType}`); - } - return { vNodeTag, isLazy }; -} - export function createFragmentVNode(fragmentKey, fragmentProps) { const vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps); vNode.shouldUpdate = true; @@ -127,7 +105,24 @@ export function createPortalVNode(portal) { } export function createUndeterminedVNode(type, key, props) { - const { vNodeTag, isLazy } = getVNodeTag(type); + let vNodeTag = ClsOrFunComponent; + let isLazy = false; + const componentType = typeof type; + + if (componentType === 'function') { + if (isClassComponent(type)) { + vNodeTag = ClassComponent; + } + } else if (componentType === 'string') { + vNodeTag = DomComponent; + } else if (type === TYPE_SUSPENSE) { + vNodeTag = SuspenseComponent; + } else if (componentType === 'object' && type !== null && typeMap[type.vtype]) { + vNodeTag = typeMap[type.vtype]; + isLazy = type.vtype === TYPE_LAZY; + } else { + throw Error(`Component type is invalid, got: ${type == null ? type : componentType}`); + } const vNode = newVirtualNode(vNodeTag, key, props); vNode.type = type; From 1d56b943798ced77bb6aadd08cd46eea363af9bc Mon Sep 17 00:00:00 2001 From: * <8> Date: Thu, 17 Feb 2022 20:31:09 +0800 Subject: [PATCH 34/35] Match-id-f9bbfe5ee974a8d2e4c64df540e049d0d32a2564 --- .../src/event/simulatedEvtHandler/ChangeEventHandler.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts index 7a0ca02f..c0ad947d 100644 --- a/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts +++ b/libs/horizon/src/event/simulatedEvtHandler/ChangeEventHandler.ts @@ -1,4 +1,4 @@ -import {createCustomEvent} from '../customEvents/EventFactory'; +import {decorateNativeEvent} from '../customEvents/EventFactory'; import {getDom} from '../../dom/DOMInternalKeys'; import {isInputValueChanged} from '../../dom/valueHandler/ValueChangeHandler'; import {addValueUpdateList} from '../ControlledValueUpdater'; @@ -48,11 +48,10 @@ export function getListeners( // 判断是否需要触发change事件 if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) { addValueUpdateList(target); - const event = createCustomEvent( + const event = decorateNativeEvent( 'onChange', 'change', nativeEvt, - target, ); return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL); } From 3f9bcc8c577f9a677256cadf93f8818334c015d7 Mon Sep 17 00:00:00 2001 From: * <8> Date: Fri, 18 Feb 2022 10:23:44 +0800 Subject: [PATCH 35/35] Match-id-85dc02bf87a8af162660f3bac0e8edd29c29323d --- libs/horizon/src/renderer/submit/LifeCycleHandler.ts | 2 +- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index a9d8344d..dd68847b 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -235,7 +235,7 @@ function submitAddition(vNode: VNode): void { parent = parent.parent; } - if ((vNode.flags & ResetText) === ResetText) { + if ((parent.flags & ResetText) === ResetText) { // 在insert之前先reset clearText(parentDom); FlagUtils.removeFlag(parent, ResetText); diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index cc56591c..400ee792 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -93,7 +93,6 @@ export function clearVNode(vNode: VNode) { vNode.oldState = null; vNode.oldRef = null; vNode.oldChild = null; - vNode.flags = InitFlag; vNode.toUpdateNodes = null;