From 02aad2cad043a482c7f732166081e27b15b4f532 Mon Sep 17 00:00:00 2001 From: * <8> Date: Mon, 21 Feb 2022 17:06:07 +0800 Subject: [PATCH 01/11] Match-id-da82a2aa9908dd57e3cfbc3ee740347081aca5d6 --- libs/horizon/src/renderer/UpdateHandler.ts | 24 +++++++++---------- .../src/renderer/render/ClassComponent.ts | 2 -- .../src/renderer/render/DomComponent.ts | 6 +---- libs/horizon/src/renderer/vnode/VNode.ts | 1 + .../src/renderer/vnode/VNodeCreator.ts | 5 ++-- 5 files changed, 16 insertions(+), 22 deletions(-) diff --git a/libs/horizon/src/renderer/UpdateHandler.ts b/libs/horizon/src/renderer/UpdateHandler.ts index a2b55485..e50d1e21 100644 --- a/libs/horizon/src/renderer/UpdateHandler.ts +++ b/libs/horizon/src/renderer/UpdateHandler.ts @@ -18,11 +18,6 @@ export enum UpdateState { Error = 'Error', } -// 初始化更新数组 -export function createUpdateArray(vNode: VNode): void { - vNode.updates = []; // 新产生的update会加入这个数组 -} - // 创建update对象 export function newUpdate(): Update { return { @@ -35,8 +30,11 @@ export function newUpdate(): Update { // 将update对象加入updates export function pushUpdate(vNode: VNode, update: Update) { const updates = vNode.updates; - - updates?.push(update); + if (updates !== null) { + updates.push(update); + } else { + vNode.updates = [update]; + } } // 根据update获取新的state @@ -98,12 +96,14 @@ export function processUpdates(vNode: VNode, inst: any, props: any): void { const updates: Updates = vNode.updates; vNode.isForceUpdate = false; - const toProcessUpdates = [...updates]; - updates.length = 0; - - if (toProcessUpdates.length) { - calcUpdates(vNode, props, inst, toProcessUpdates); + if (updates !== null) { + const toProcessUpdates = [...updates]; + updates.length = 0; + if (toProcessUpdates.length) { + calcUpdates(vNode, props, inst, toProcessUpdates); + } } + } export function pushForceUpdate(vNode: VNode) { diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index 261fea3f..36b15707 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -23,7 +23,6 @@ import { import { FlagUtils, DidCapture } from '../vnode/VNodeFlags'; import { markRef } from './BaseComponent'; import { - createUpdateArray, processUpdates, } from '../UpdateHandler'; import { getContextChangeCtx, setContextChangeCtx } from '../ContextSaver'; @@ -55,7 +54,6 @@ function mountInstance(clazz, processing: VNode, nextProps: object) { inst.context = getCurrentContext(clazz, processing); inst.refs = {}; - createUpdateArray(processing); processUpdates(processing, inst, nextProps); inst.state = processing.state; diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index ace8f10f..8baf71e4 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -105,7 +105,7 @@ export function bubbleRender(processing: VNode) { } } -function captureDomComponent(processing: VNode): VNode | null { +export function captureRender(processing: VNode): VNode | null { setNamespaceCtx(processing); const type = processing.type; @@ -127,7 +127,3 @@ function captureDomComponent(processing: VNode): VNode | null { processing.child = createChildrenByDiff(processing, processing.child, nextChildren, !processing.isCreated); return processing.child; } - -export function captureRender(processing: VNode): VNode | null { - return captureDomComponent(processing); -} diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index a48c4ab9..129e54a8 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -138,6 +138,7 @@ export class VNode { this.stateCallbacks = null; this.isLazyComponent = true; this.lazyType = null; + this.updates = null; break; case Fragment: break; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 35b1b354..5305b13a 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -16,7 +16,6 @@ import { MemoComponent, SuspenseComponent, } from './VNodeTags'; -import { createUpdateArray } from '../UpdateHandler'; import { TYPE_CONTEXT, TYPE_FORWARD_REF, TYPE_FRAGMENT, @@ -137,7 +136,7 @@ export function createUndeterminedVNode(type, key, props) { export function createTreeRootVNode(container) { const vNode = newVirtualNode(TreeRoot, null, null, container); vNode.path += 0; - createUpdateArray(vNode); + vNode.updates = []; return vNode; } @@ -150,7 +149,7 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) { vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]); vNode.path += 0; - createUpdateArray(vNode); + vNode.updates = []; break; } From c6c4ec9caa19df5ce841cb81f98defa12ad9a291 Mon Sep 17 00:00:00 2001 From: * <8> Date: Mon, 21 Feb 2022 17:43:04 +0800 Subject: [PATCH 02/11] Match-id-a915f78dcc8ebc19fdc1e4577d27d7bd4cd75d4a --- .../renderer/render/class/ClassLifeCycleProcessor.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts b/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts index 90f662c3..153094e0 100644 --- a/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts +++ b/libs/horizon/src/renderer/render/class/ClassLifeCycleProcessor.ts @@ -118,15 +118,19 @@ export function callComponentWillUpdate(inst, newProps, newState, nextContext) { } export function callComponentWillReceiveProps(inst, newProps: object, newContext: object) { - const oldState = inst.state; if (inst.componentWillReceiveProps) { + const oldState = inst.state; inst.componentWillReceiveProps(newProps, newContext); + if (inst.state !== oldState) { + changeStateContent.call(inst, UpdateState.Override, inst.state, null); + } } if (inst.UNSAFE_componentWillReceiveProps) { + const oldState = inst.state; inst.UNSAFE_componentWillReceiveProps(newProps, newContext); - } - if (inst.state !== oldState) { - changeStateContent.call(inst, UpdateState.Override, inst.state, null); + if (inst.state !== oldState) { + changeStateContent.call(inst, UpdateState.Override, inst.state, null); + } } } From 496549d482a5b76660344cca1ed0c95a6c4cb0e9 Mon Sep 17 00:00:00 2001 From: * <8> Date: Mon, 21 Feb 2022 18:02:29 +0800 Subject: [PATCH 03/11] Match-id-cad8c111829404e1a2aecd5d519f4f3a14c2670e --- libs/horizon/src/renderer/TreeBuilder.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 76de8ae4..45b21eaa 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -59,11 +59,11 @@ function collectDirtyNodes(vNode: VNode, parent: VNode): void { const dirtyNodes = vNode.dirtyNodes; if (dirtyNodes !== null && dirtyNodes.length) { if (parent.dirtyNodes === null) { - parent.dirtyNodes = [...vNode.dirtyNodes]; + parent.dirtyNodes = dirtyNodes; } else { parent.dirtyNodes.push(...vNode.dirtyNodes); + dirtyNodes.length = 0; } - dirtyNodes.length = 0; vNode.dirtyNodes = null; } From 1ed7e608cc5e3246c874e9df4484b969914a1ab5 Mon Sep 17 00:00:00 2001 From: * <8> Date: Tue, 22 Feb 2022 10:13:35 +0800 Subject: [PATCH 04/11] Match-id-6208d162f4af32a98c0b3a08ba5648aefc074f3b --- libs/horizon/src/event/HorizonEventMain.ts | 6 ++++-- libs/horizon/src/event/utils.ts | 9 --------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/libs/horizon/src/event/HorizonEventMain.ts b/libs/horizon/src/event/HorizonEventMain.ts index c550fdbe..08e9f5d0 100644 --- a/libs/horizon/src/event/HorizonEventMain.ts +++ b/libs/horizon/src/event/HorizonEventMain.ts @@ -10,7 +10,7 @@ import { import { getListeners as getChangeListeners } from './simulatedEvtHandler/ChangeEventHandler'; import { getListeners as getSelectionListeners } from './simulatedEvtHandler/SelectionEventHandler'; import { - addOnPrefix, setPropertyWritable, + setPropertyWritable, } from './utils'; import { decorateNativeEvent } from './customEvents/EventFactory'; import { getListenersFromTree } from './ListenerGetter'; @@ -27,7 +27,9 @@ function getCommonListeners( target: null | EventTarget, isCapture: boolean, ): ListenerUnitList { - const horizonEvtName = addOnPrefix(CommonEventToHorizonMap[nativeEvtName]); + const name = CommonEventToHorizonMap[nativeEvtName]; + const horizonEvtName = !name ? '' : `on${name[0].toUpperCase()}${name.slice(1)}`; // 例:dragEnd -> onDragEnd + if (!horizonEvtName) { return []; } diff --git a/libs/horizon/src/event/utils.ts b/libs/horizon/src/event/utils.ts index d4b6f143..09d1b240 100644 --- a/libs/horizon/src/event/utils.ts +++ b/libs/horizon/src/event/utils.ts @@ -6,15 +6,6 @@ export function isInputElement(dom?: HTMLElement): boolean { return false; } - -// 例:dragEnd -> onDragEnd -export function addOnPrefix(name) { - if (!name) { - return ''; - } - return 'on' + name[0].toUpperCase() + name.slice(1); -} - export function setPropertyWritable(obj, propName) { const desc = Object.getOwnPropertyDescriptor(obj, propName); if (!desc || !desc.writable) { From 4d173bd7a02c5fd85db83d8f4ea817c2d1ba40b3 Mon Sep 17 00:00:00 2001 From: * <8> Date: Tue, 22 Feb 2022 16:46:32 +0800 Subject: [PATCH 05/11] Match-id-7839b5cc6a49de4445d87b458c40a79570ade7ba --- .../DOMPropertiesHandler.ts | 60 +++++++++++-------- 1 file changed, 36 insertions(+), 24 deletions(-) diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts index 496d0c2c..9b272aaf 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts @@ -8,28 +8,6 @@ import { } from '../../event/EventBinding'; import { isEventProp, isNativeElement } from '../validators/ValidateProps'; -function updateOneProp(dom, propName, isNativeTag, propVal?, isInit?: boolean) { - if (propName === 'style') { - setStyles(dom, 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); - } - } -} - // 初始化DOM属性 export function setDomProps( tagName: string, @@ -45,7 +23,25 @@ export function setDomProps( propName = keysOfProps[i]; propVal = props[propName]; - updateOneProp(dom, propName, isNativeTag, propVal, true); + if (propName === 'style') { + setStyles(dom, 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 (propVal != null) { + updateCommonProp(dom, propName, propVal, isNativeTag); + } + } } } @@ -56,7 +52,23 @@ export function updateDomProps( isNativeTag: boolean, ): void { for(const [propName, propVal] of changeList) { - updateOneProp(dom, propName, isNativeTag, propVal); + if (propName === 'style') { + setStyles(dom, 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 { + updateCommonProp(dom, propName, propVal, isNativeTag); + } } } From 5dd5a506633efd3102f443b1cfda23870f17cfd9 Mon Sep 17 00:00:00 2001 From: * <8> Date: Tue, 22 Feb 2022 16:56:23 +0800 Subject: [PATCH 06/11] Match-id-c11e1befe0eb42e72a1ff5aeab9cd80718bdf2ae --- libs/horizon/src/renderer/TreeBuilder.ts | 2 +- libs/horizon/src/renderer/Types.ts | 2 +- .../src/renderer/components/CreatePortal.ts | 4 ++-- .../src/renderer/diff/nodeDiffComparator.ts | 4 ++-- .../src/renderer/render/BaseComponent.ts | 4 ++-- libs/horizon/src/renderer/render/DomPortal.ts | 4 ++-- libs/horizon/src/renderer/render/TreeRoot.ts | 2 +- .../src/renderer/submit/LifeCycleHandler.ts | 17 ++++------------- libs/horizon/src/renderer/vnode/VNode.ts | 6 ++---- libs/horizon/src/renderer/vnode/VNodeCreator.ts | 6 +++--- libs/horizon/src/renderer/vnode/VNodeUtils.ts | 4 ++-- 11 files changed, 22 insertions(+), 33 deletions(-) diff --git a/libs/horizon/src/renderer/TreeBuilder.ts b/libs/horizon/src/renderer/TreeBuilder.ts index 45b21eaa..7eca2c59 100644 --- a/libs/horizon/src/renderer/TreeBuilder.ts +++ b/libs/horizon/src/renderer/TreeBuilder.ts @@ -236,7 +236,7 @@ function buildVNodeTree(treeRoot: VNode) { // 当在componentWillUnmount中调用setState,parent可能是null,因为startVNode会被clear if (parent !== null) { resetNamespaceCtx(parent); - setNamespaceCtx(parent, parent.outerDom); + setNamespaceCtx(parent, parent.realNode); } // 恢复父节点的context diff --git a/libs/horizon/src/renderer/Types.ts b/libs/horizon/src/renderer/Types.ts index 9acbc42c..f95c4720 100644 --- a/libs/horizon/src/renderer/Types.ts +++ b/libs/horizon/src/renderer/Types.ts @@ -39,7 +39,7 @@ export type ContextType = { export type PortalType = { vtype: number; key: null | string; - outerDom: any; + realNode: any; children: any; }; diff --git a/libs/horizon/src/renderer/components/CreatePortal.ts b/libs/horizon/src/renderer/components/CreatePortal.ts index 38d30ca8..9e5e6a65 100644 --- a/libs/horizon/src/renderer/components/CreatePortal.ts +++ b/libs/horizon/src/renderer/components/CreatePortal.ts @@ -3,13 +3,13 @@ import type {PortalType} from '../Types'; export function createPortal( children: any, - outerDom: any, + realNode: any, key: string = '', ): PortalType { return { vtype: TYPE_PORTAL, key: key == '' ? '' : '' + key, children, - outerDom, + realNode, }; } diff --git a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts index d3033570..f5cb03f9 100644 --- a/libs/horizon/src/renderer/diff/nodeDiffComparator.ts +++ b/libs/horizon/src/renderer/diff/nodeDiffComparator.ts @@ -153,7 +153,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) { } break; } else if (newChild.vtype === TYPE_PORTAL) { - if (oldNode === null || oldNode.tag !== DomPortal || oldNode.outerDom !== newChild.outerDom) { + if (oldNode === null || oldNode.tag !== DomPortal || oldNode.realNode !== newChild.realNode) { resultNode = createPortalVNode(newChild); } else { resultNode = updateVNode(oldNode, newChild.children || []); @@ -578,7 +578,7 @@ function diffObjectNodeHandler( } else if (newChild.vtype === TYPE_PORTAL) { if (canReuseNode) { // 可以复用 - if (canReuseNode.tag === DomPortal && canReuseNode.outerDom === newChild.outerDom) { + if (canReuseNode.tag === DomPortal && canReuseNode.realNode === newChild.realNode) { resultNode = updateVNode(canReuseNode, newChild.children || []); startDelVNode = canReuseNode.next; resultNode.next = null; diff --git a/libs/horizon/src/renderer/render/BaseComponent.ts b/libs/horizon/src/renderer/render/BaseComponent.ts index afedf488..c94d815d 100644 --- a/libs/horizon/src/renderer/render/BaseComponent.ts +++ b/libs/horizon/src/renderer/render/BaseComponent.ts @@ -18,7 +18,7 @@ import componentRenders from './index'; function handlerContext(processing: VNode) { switch (processing.tag) { case TreeRoot: - setNamespaceCtx(processing, processing.outerDom); + setNamespaceCtx(processing, processing.realNode); break; case DomComponent: setNamespaceCtx(processing); @@ -29,7 +29,7 @@ function handlerContext(processing: VNode) { break; } case DomPortal: - setNamespaceCtx(processing, processing.outerDom); + setNamespaceCtx(processing, processing.realNode); break; case ContextProvider: { const newValue = processing.props.value; diff --git a/libs/horizon/src/renderer/render/DomPortal.ts b/libs/horizon/src/renderer/render/DomPortal.ts index d3f79e58..baf4b500 100644 --- a/libs/horizon/src/renderer/render/DomPortal.ts +++ b/libs/horizon/src/renderer/render/DomPortal.ts @@ -7,12 +7,12 @@ export function bubbleRender(processing: VNode) { resetNamespaceCtx(processing); if (processing.isCreated) { - prePortal(processing.outerDom); + prePortal(processing.realNode); } } function capturePortalComponent(processing: VNode) { - setNamespaceCtx(processing, processing.outerDom); + setNamespaceCtx(processing, processing.realNode); const newElements = processing.props; if (processing.isCreated) { diff --git a/libs/horizon/src/renderer/render/TreeRoot.ts b/libs/horizon/src/renderer/render/TreeRoot.ts index 9b5eaa86..33a28402 100644 --- a/libs/horizon/src/renderer/render/TreeRoot.ts +++ b/libs/horizon/src/renderer/render/TreeRoot.ts @@ -12,7 +12,7 @@ export function bubbleRender(processing: VNode) { } function updateTreeRoot(processing) { - setNamespaceCtx(processing, processing.outerDom); + setNamespaceCtx(processing, processing.realNode); const updates = processing.updates; throwIfTrue( diff --git a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts index 5d8d649a..adb21135 100644 --- a/libs/horizon/src/renderer/submit/LifeCycleHandler.ts +++ b/libs/horizon/src/renderer/submit/LifeCycleHandler.ts @@ -225,12 +225,9 @@ function submitAddition(vNode: VNode): void { let tag; while (parent !== null) { tag = parent.tag; - if (tag === DomComponent) { + if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) { parentDom = parent.realNode; break; - } else if (tag === TreeRoot || tag === DomPortal) { - parentDom = parent.outerDom; - break; } parent = parent.parent; } @@ -292,12 +289,9 @@ function unmountDomComponents(vNode: VNode): void { let tag; while (parent !== null) { tag = parent.tag; - if (tag === DomComponent) { + if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) { currentParent = parent.realNode; break; - } else if (tag === TreeRoot || tag === DomPortal) { - currentParent = parent.outerDom; - break; } parent = parent.parent; } @@ -312,7 +306,7 @@ function unmountDomComponents(vNode: VNode): void { removeChildDom(currentParent, node.realNode); } else if (node.tag === DomPortal) { if (node.child !== null) { - currentParent = node.outerDom; + currentParent = node.realNode; } } else { unmountVNode(node); @@ -349,12 +343,9 @@ function submitClear(vNode: VNode): void { let tag; while (parent !== null) { tag = parent.tag; - if (tag === DomComponent) { + if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) { parentDom = parent.realNode; break; - } else if (tag === TreeRoot || tag === DomPortal) { - parentDom = parent.outerDom; - break; } parent = parent.parent; } diff --git a/libs/horizon/src/renderer/vnode/VNode.ts b/libs/horizon/src/renderer/vnode/VNode.ts index 129e54a8..b076a3eb 100644 --- a/libs/horizon/src/renderer/vnode/VNode.ts +++ b/libs/horizon/src/renderer/vnode/VNode.ts @@ -39,7 +39,6 @@ export class VNode { dirtyNodes: Array | null = null; // 需要改动的节点数组 shouldUpdate: boolean = false; childShouldUpdate: boolean = false; - outerDom: any; task: any; // 使用这个变量来记录修改前的值,用于恢复。 @@ -67,7 +66,7 @@ export class VNode { belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用 - constructor(tag: VNodeTag, props: any, key: null | string, outerDom) { + constructor(tag: VNodeTag, props: any, key: null | string, realNode) { this.tag = tag; // 对应组件的类型,比如ClassComponent等 this.key = key; @@ -75,10 +74,9 @@ export class VNode { switch (tag) { case TreeRoot: - this.outerDom = outerDom; + this.realNode = realNode; this.task = null; this.toUpdateNodes = new Set(); - this.realNode = null; this.updates = null; this.stateCallbacks = null; this.state = null; diff --git a/libs/horizon/src/renderer/vnode/VNodeCreator.ts b/libs/horizon/src/renderer/vnode/VNodeCreator.ts index 5305b13a..972a006f 100644 --- a/libs/horizon/src/renderer/vnode/VNodeCreator.ts +++ b/libs/horizon/src/renderer/vnode/VNodeCreator.ts @@ -38,8 +38,8 @@ const typeMap = { [TYPE_LAZY]: LazyComponent, }; -const newVirtualNode = function(tag: VNodeTag, key?: null | string, vNodeProps?: any, outerDom?: any): VNode { - return new VNode(tag, vNodeProps, key, outerDom); +const newVirtualNode = function(tag: VNodeTag, key?: null | string, vNodeProps?: any, realNode?: any): VNode { + return new VNode(tag, vNodeProps, key, realNode); }; function isClassComponent(comp: Function) { @@ -99,7 +99,7 @@ export function createPortalVNode(portal) { const children = portal.children ?? []; const vNode = newVirtualNode(DomPortal, portal.key, children); vNode.shouldUpdate = true; - vNode.outerDom = portal.outerDom; + vNode.realNode = portal.realNode; return vNode; } diff --git a/libs/horizon/src/renderer/vnode/VNodeUtils.ts b/libs/horizon/src/renderer/vnode/VNodeUtils.ts index a6521757..acda0b39 100644 --- a/libs/horizon/src/renderer/vnode/VNodeUtils.ts +++ b/libs/horizon/src/renderer/vnode/VNodeUtils.ts @@ -210,7 +210,7 @@ function isPortalRoot(vNode, targetContainer) { while (topVNode !== null) { const grandTag = topVNode.tag; if (grandTag === TreeRoot || grandTag === DomPortal) { - const topContainer = topVNode.outerDom; + const topContainer = topVNode.realNode; // 如果topContainer是targetContainer,不需要在这里处理 if (isSameContainer(topContainer, targetContainer)) { return true; @@ -229,7 +229,7 @@ export function getExactNode(targetVNode, targetContainer) { let vNode = targetVNode; while (vNode !== null) { if (vNode.tag === TreeRoot || vNode.tag === DomPortal) { - let container = vNode.outerDom; + let container = vNode.realNode; if (isSameContainer(container, targetContainer)) { break; } From 46c4e406b1e22103dc209b16d61f17de812ccc66 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 23 Feb 2022 14:15:01 +0800 Subject: [PATCH 07/11] Match-id-50484ea25531ddb0401803d9939d3ffa068a783f --- libs/horizon/src/renderer/render/ClassComponent.ts | 10 ++-------- libs/horizon/src/renderer/vnode/VNodeFlags.ts | 6 ++---- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index 36b15707..83cccb11 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -46,9 +46,8 @@ function mountInstance(clazz, processing: VNode, nextProps: object) { } // 构造实例 - callConstructor(processing, clazz, nextProps); + const inst = callConstructor(processing, clazz, nextProps); - const inst = processing.realNode; inst.props = nextProps; inst.state = processing.state; inst.context = getCurrentContext(clazz, processing); @@ -121,18 +120,13 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps: const newContext = getCurrentContext(clazz, processing); // 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props - let oldProps = (processing.flags & DidCapture) === DidCapture ? processing.props : processing.oldProps; - if (processing.isLazyComponent) { - oldProps = mergeDefaultProps(processing.type, oldProps); - } - inst.props = oldProps; + const oldProps = (processing.flags & DidCapture) === DidCapture ? processing.props : processing.oldProps; if (oldProps !== processing.props || inst.context !== newContext) { // 在已挂载的组件接收新的 props 之前被调用 callComponentWillReceiveProps(inst, nextProps, newContext); } - inst.state = processing.state; processUpdates(processing, inst, nextProps); // 如果 props, state, context 都没有变化且 isForceUpdate 为 false则不需要更新 diff --git a/libs/horizon/src/renderer/vnode/VNodeFlags.ts b/libs/horizon/src/renderer/vnode/VNodeFlags.ts index af0c2fad..91f59d35 100644 --- a/libs/horizon/src/renderer/vnode/VNodeFlags.ts +++ b/libs/horizon/src/renderer/vnode/VNodeFlags.ts @@ -24,12 +24,10 @@ const LifecycleEffectArr = Update | Callback | Ref | Snapshot; export class FlagUtils { static removeFlag(node: VNode, flag: number) { - const flags = node.flags; - node.flags = flags & (~flag); + node.flags &= ~flag; } static removeLifecycleEffectFlags(node) { - const flags = node.flags; - node.flags = flags & (~LifecycleEffectArr); + node.flags &= ~LifecycleEffectArr; } static hasAnyFlag(node: VNode) { // 有标志位 return node.flags !== InitFlag; From b7183f10827eb2a5f6222dcd14922e1e10927009 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 23 Feb 2022 14:51:46 +0800 Subject: [PATCH 08/11] Match-id-97c0af573376bf091e9db7228d7cea81484ba94a --- .../src/renderer/render/ClassComponent.ts | 17 +++++++++-------- .../src/renderer/render/LazyComponent.ts | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/libs/horizon/src/renderer/render/ClassComponent.ts b/libs/horizon/src/renderer/render/ClassComponent.ts index 83cccb11..6db4dcf2 100644 --- a/libs/horizon/src/renderer/render/ClassComponent.ts +++ b/libs/horizon/src/renderer/render/ClassComponent.ts @@ -103,7 +103,15 @@ function markLifeCycle(processing: VNode, nextProps: object, shouldUpdate: Boole } // 用于类组件 -export function captureClassComponent(processing: VNode, clazz: any, nextProps: object): VNode | null { +export function captureRender(processing: VNode): VNode | null { + let clazz = processing.type; + let nextProps = processing.props; + if (processing.isLazyComponent) { + nextProps = mergeDefaultProps(clazz, nextProps); + if (processing.promiseResolve) { // 该函数被 lazy 组件使用,未加载的组件需要加载组件的真实内容 + clazz = clazz._load(clazz._content); + } + } const isOldCxtExist = isOldProvider(clazz); cacheOldCtx(processing, isOldCxtExist); @@ -175,13 +183,6 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps: } } -export function captureRender(processing: VNode): VNode | null { - const clazz = processing.type; - const props = processing.props; - const nextProps = processing.isLazyComponent ? mergeDefaultProps(clazz, props) : props; - return captureClassComponent(processing, clazz, nextProps); -} - export function bubbleRender(processing: VNode) { if (isOldProvider(processing.type)) { resetOldCtx(processing); diff --git a/libs/horizon/src/renderer/render/LazyComponent.ts b/libs/horizon/src/renderer/render/LazyComponent.ts index a1f911ad..7f81ab2a 100644 --- a/libs/horizon/src/renderer/render/LazyComponent.ts +++ b/libs/horizon/src/renderer/render/LazyComponent.ts @@ -10,7 +10,7 @@ import { } from '../vnode/VNodeTags'; import { throwIfTrue } from '../utils/throwIfTrue'; import { captureFunctionComponent } from './FunctionComponent'; -import { captureClassComponent } from './ClassComponent'; +import { captureRender as captureClassComponent } from './ClassComponent'; import { captureMemoComponent } from './MemoComponent'; export function bubbleRender() { } From 56dd409cbc7d92d7ca8069753b0e89809ca955e1 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 23 Feb 2022 15:40:07 +0800 Subject: [PATCH 09/11] Match-id-342c2da56a252520c7e3a8208993538ef34cfb23 --- libs/horizon/src/dom/DOMOperator.ts | 5 ++-- .../DOMPropertiesHandler.ts | 30 +++++++++++-------- .../src/renderer/render/DomComponent.ts | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/libs/horizon/src/dom/DOMOperator.ts b/libs/horizon/src/dom/DOMOperator.ts index bb061fa7..894ccd96 100644 --- a/libs/horizon/src/dom/DOMOperator.ts +++ b/libs/horizon/src/dom/DOMOperator.ts @@ -110,7 +110,7 @@ export function getPropChangeList( type: string, lastRawProps: Props, nextRawProps: Props, -): Map { +): Object { // 校验两个对象的不同 validateProps(type, nextRawProps); @@ -118,8 +118,7 @@ export function getPropChangeList( const oldProps: Object = getPropsWithoutValue(type, dom, lastRawProps); const newProps: Object = getPropsWithoutValue(type, dom, nextRawProps); - const changeList = compareProps(oldProps, newProps); - return changeList; + return compareProps(oldProps, newProps); } export function isTextChild(type: string, props: Props): boolean { diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts index 9b272aaf..e35e2b2a 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts @@ -48,10 +48,16 @@ export function setDomProps( // 更新 DOM 属性 export function updateDomProps( dom: Element, - changeList: Map, + changeList: Object, isNativeTag: boolean, ): void { - for(const [propName, propVal] of changeList) { + const keysOfProps = Object.keys(changeList); + let propName; + let propVal; + const keyLength = keysOfProps.length; + for(let i = 0; i < keyLength; i++) { + propName = keysOfProps[i]; + propVal = changeList[propName]; if (propName === 'style') { setStyles(dom, propVal); } else if (isEventProp(propName)) { @@ -76,9 +82,9 @@ export function updateDomProps( export function compareProps( oldProps: Object, newProps: Object, -): Map { +): Object { let updatesForStyle = {}; - const toUpdateProps = new Map(); + const toUpdateProps = {}; const keysOfOldProps = Object.keys(oldProps); const keysOfNewProps = Object.keys(newProps); @@ -110,11 +116,11 @@ export function compareProps( continue; } else if (isEventProp(propName)) { if (!allDelegatedHorizonEvents.has(propName)) { - toUpdateProps.set(propName, null); + toUpdateProps[propName] = null; } } else { // 其它属性都要加入到删除队列里面,等待删除 - toUpdateProps.set(propName, null); + toUpdateProps[propName] = null; } } @@ -156,7 +162,7 @@ export function compareProps( } } else { // 之前未设置 style 属性或者设置了空值 if (Object.keys(updatesForStyle).length === 0) { - toUpdateProps.set(propName, null); + toUpdateProps[propName] = null; } updatesForStyle = newPropValue; } @@ -165,25 +171,25 @@ export function compareProps( oldHTML = oldPropValue ? oldPropValue.__html : undefined; if (newHTML != null) { if (oldHTML !== newHTML) { - toUpdateProps.set(propName, newPropValue); + toUpdateProps[propName] = newPropValue; } } } else if (propName === 'children') { if (typeof newPropValue === 'string' || typeof newPropValue === 'number') { - toUpdateProps.set(propName, String(newPropValue)); + toUpdateProps[propName] = String(newPropValue); } } else if (isEventProp(propName)) { if (!allDelegatedHorizonEvents.has(propName)) { - toUpdateProps.set(propName, newPropValue); + toUpdateProps[propName] = newPropValue; } } else { - toUpdateProps.set(propName, newPropValue); + toUpdateProps[propName] = newPropValue; } } // 处理style if (Object.keys(updatesForStyle).length > 0) { - toUpdateProps.set('style', updatesForStyle); + toUpdateProps['style'] = updatesForStyle; } return toUpdateProps; diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index 8baf71e4..7d5a0503 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -45,7 +45,7 @@ function updateDom( FlagUtils.markUpdate(processing); } else { // 其它的类型,数据有变化才标记更新 - if (changeList.size) { + if (Object.keys(changeList).length) { FlagUtils.markUpdate(processing); } } From 0492221e891fb8f7bc22473679af41a42fae2d71 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 23 Feb 2022 15:48:09 +0800 Subject: [PATCH 10/11] Match-id-3b7b120ab54faf76b7553ae54f60d9051d419781 --- libs/horizon/src/renderer/render/DomComponent.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libs/horizon/src/renderer/render/DomComponent.ts b/libs/horizon/src/renderer/render/DomComponent.ts index 7d5a0503..5e8e5164 100644 --- a/libs/horizon/src/renderer/render/DomComponent.ts +++ b/libs/horizon/src/renderer/render/DomComponent.ts @@ -38,14 +38,15 @@ function updateDom( oldProps, newProps, ); - processing.changeList = changeList; // 输入类型的直接标记更新 if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') { FlagUtils.markUpdate(processing); + processing.changeList = changeList; } else { // 其它的类型,数据有变化才标记更新 if (Object.keys(changeList).length) { + processing.changeList = changeList; FlagUtils.markUpdate(processing); } } From a36f7f9260ca38800854b464e055a9c9762ce986 Mon Sep 17 00:00:00 2001 From: * <8> Date: Wed, 23 Feb 2022 16:15:21 +0800 Subject: [PATCH 11/11] Match-id-cd373c95d0b3324947f005897eb475632af01f79 --- libs/horizon/src/dom/DOMOperator.ts | 7 +-- .../DOMPropertiesHandler.ts | 45 +++---------------- 2 files changed, 9 insertions(+), 43 deletions(-) diff --git a/libs/horizon/src/dom/DOMOperator.ts b/libs/horizon/src/dom/DOMOperator.ts index 894ccd96..073456fc 100644 --- a/libs/horizon/src/dom/DOMOperator.ts +++ b/libs/horizon/src/dom/DOMOperator.ts @@ -19,7 +19,7 @@ import { } from './valueHandler'; import { compareProps, - setDomProps, updateDomProps + setDomProps, } from './DOMPropertiesHandler/DOMPropertiesHandler'; import { isNativeElement, validateProps } from './validators/ValidateProps'; import { watchValueChange } from './valueHandler/ValueChangeHandler'; @@ -91,7 +91,8 @@ export function initDomProps(dom: Element, tagName: string, rawProps: Props): bo const props: Object = getPropsWithoutValue(tagName, dom, rawProps); // 初始化DOM属性(不包括value,defaultValue) - setDomProps(tagName, dom, props); + const isNativeTag = isNativeElement(tagName, props); + setDomProps(dom, props, isNativeTag, true); if (tagName === 'input' || tagName === 'textarea') { // 增加监听value和checked的set、get方法 @@ -167,7 +168,7 @@ export function submitDomUpdate(tag: string, vNode: VNode) { updateCommonProp(element, 'checked', newProps.checked, true); } const isNativeTag = isNativeElement(type, newProps); - updateDomProps(element, changeList, isNativeTag); + setDomProps(element, changeList, isNativeTag, false); updateValue(type, element, newProps); } } diff --git a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts index e35e2b2a..c7f76f2f 100644 --- a/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts +++ b/libs/horizon/src/dom/DOMPropertiesHandler/DOMPropertiesHandler.ts @@ -6,15 +6,15 @@ import { setStyles } from './StyleHandler'; import { listenNonDelegatedEvent } from '../../event/EventBinding'; -import { isEventProp, isNativeElement } from '../validators/ValidateProps'; +import { isEventProp } from '../validators/ValidateProps'; -// 初始化DOM属性 +// 初始化DOM属性和更新 DOM 属性 export function setDomProps( - tagName: string, dom: Element, props: Object, + isNativeTag: boolean, + isInit: boolean, ): void { - const isNativeTag = isNativeElement(tagName, props); const keysOfProps = Object.keys(props); let propName; let propVal; @@ -37,42 +37,7 @@ export function setDomProps( } } else if (propName === 'dangerouslySetInnerHTML') { dom.innerHTML = propVal.__html; - } else { - if (propVal != null) { - updateCommonProp(dom, propName, propVal, isNativeTag); - } - } - } -} - -// 更新 DOM 属性 -export function updateDomProps( - dom: Element, - changeList: Object, - isNativeTag: boolean, -): void { - const keysOfProps = Object.keys(changeList); - let propName; - let propVal; - const keyLength = keysOfProps.length; - for(let i = 0; i < keyLength; i++) { - propName = keysOfProps[i]; - propVal = changeList[propName]; - if (propName === 'style') { - setStyles(dom, 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 { + } else if (!isInit || (isInit && propVal != null)) { updateCommonProp(dom, propName, propVal, isNativeTag); } }