Match-id-59c29ddd1605197746f6eed11f5df8bff5f7c3e7

This commit is contained in:
* 2022-01-30 16:31:33 +08:00 committed by *
commit 315b878df0
17 changed files with 157 additions and 177 deletions

View File

@ -1,13 +1,13 @@
import { import {
asyncUpdates, createVNode, getFirstCustomDom, asyncUpdates, getFirstCustomDom,
syncUpdates, startUpdate, syncUpdates, startUpdate,
createTreeRootVNode,
} from '../renderer/Renderer'; } from '../renderer/Renderer';
import {createPortal} from '../renderer/components/CreatePortal'; import {createPortal} from '../renderer/components/CreatePortal';
import type {Container} from './DOMOperator'; import type {Container} from './DOMOperator';
import {isElement} from './utils/Common'; import {isElement} from './utils/Common';
import {listenDelegatedEvents} from '../event/EventBinding'; import {listenDelegatedEvents} from '../event/EventBinding';
import {findDOMByClassInst} from '../renderer/vnode/VNodeUtils'; import {findDOMByClassInst} from '../renderer/vnode/VNodeUtils';
import {TreeRoot} from '../renderer/vnode/VNodeTags';
import {Callback} from '../renderer/UpdateHandler'; import {Callback} from '../renderer/UpdateHandler';
function createRoot(children: any, container: Container, callback?: Callback) { function createRoot(children: any, container: Container, callback?: Callback) {
@ -19,7 +19,7 @@ function createRoot(children: any, container: Container, callback?: Callback) {
} }
// 调度器创建根节点并给容器dom赋vNode结构体 // 调度器创建根节点并给容器dom赋vNode结构体
const treeRoot = createVNode(TreeRoot, container); const treeRoot = createTreeRootVNode(container);
container._treeRoot = treeRoot; container._treeRoot = treeRoot;
// 根节点挂接全量事件 // 根节点挂接全量事件

View File

@ -91,7 +91,7 @@ export function getEventListeners(dom: EventTarget): Set<string> {
return elementListeners; return elementListeners;
} }
export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> { export function getNonDelegatedListenerMap(target: EventTarget): Map<string, EventListener> {
let eventsMap = target[internalKeys.nonDelegatedEvents]; let eventsMap = target[internalKeys.nonDelegatedEvents];
if (!eventsMap) { if (!eventsMap) {
eventsMap = new Map(); eventsMap = new Map();

View File

@ -21,6 +21,7 @@ import {
getTextareaPropsWithoutValue, getTextareaPropsWithoutValue,
updateTextareaValue, updateTextareaValue,
} from './TextareaValueHandler'; } from './TextareaValueHandler';
import {getDomTag} from "../utils/Common";
// 获取元素除了被代理的值以外的属性 // 获取元素除了被代理的值以外的属性
function getPropsWithoutValue(type: string, dom: HorizonDom, properties: IProperty) { function getPropsWithoutValue(type: string, dom: HorizonDom, properties: IProperty) {
@ -72,7 +73,8 @@ function updateValue(type: string, dom: HorizonDom, properties: IProperty) {
} }
} }
function resetValue(dom: HorizonDom, type: string, properties: IProperty) { function resetValue(dom: HorizonDom, properties: IProperty) {
const type = getDomTag(dom);
switch (type) { switch (type) {
case 'input': case 'input':
resetInputValue(<HTMLInputElement>dom, properties); resetInputValue(<HTMLInputElement>dom, properties);

View File

@ -1,15 +1,13 @@
import {getVNodeProps} from '../dom/DOMInternalKeys'; import {getVNodeProps} from '../dom/DOMInternalKeys';
import {resetValue} from '../dom/valueHandler'; import {resetValue} from '../dom/valueHandler';
import {getDomTag} from '../dom/utils/Common';
let updateList = null; let updateList: Array<any> | null = null;
// 受控组件值重新赋值 // 受控组件值重新赋值
function updateValue(target: Element) { function updateValue(target: Element) {
const props = getVNodeProps(target); const props = getVNodeProps(target);
if (props) { if (props) {
const type = getDomTag(target); resetValue(target, props);
resetValue(target, type, props);
} }
} }

View File

@ -1,20 +1,21 @@
/** /**
* *
*/ */
import {allDelegatedNativeEvents} from './EventCollection'; import {allDelegatedNativeEvents} from './EventCollection';
import {isDocument} from '../dom/utils/Common'; import {isDocument} from '../dom/utils/Common';
import { import {
getEventListeners, getEventListeners,
getEventToListenerMap, getNearestVNode,
getNonDelegatedListenerMap,
} from '../dom/DOMInternalKeys'; } from '../dom/DOMInternalKeys';
import {createCustomEventListener} from './WrapperListener';
import {CustomBaseEvent} from './customEvents/CustomBaseEvent'; import {CustomBaseEvent} from './customEvents/CustomBaseEvent';
import {runDiscreteUpdates} from '../renderer/TreeBuilder';
import {getEventTarget} from './utils';
import {isMounted} from '../renderer/vnode/VNodeUtils';
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
import {handleEventMain} from './HorizonEventMain';
const listeningMarker = const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4);
'_horizonListening' +
Math.random()
.toString(36)
.slice(4);
// 获取节点上已经委托事件名称 // 获取节点上已经委托事件名称
function getListenerSetKey(nativeEvtName: string, isCapture: boolean): string { function getListenerSetKey(nativeEvtName: string, isCapture: boolean): string {
@ -22,6 +23,33 @@ function getListenerSetKey(nativeEvtName: string, isCapture: boolean): string {
return `${nativeEvtName}__${sufix}`; return `${nativeEvtName}__${sufix}`;
} }
// 触发委托事件
function triggerDelegatedEvent(
nativeEvtName: string,
isCapture: boolean,
targetDom: EventTarget,
nativeEvent, // 事件对象event
) {
// 执行之前的调度事件
runDiscreteUpdates();
const nativeEventTarget = getEventTarget(nativeEvent);
let targetVNode = getNearestVNode(nativeEventTarget);
if (targetVNode !== null) {
if (isMounted(targetVNode)) {
if (targetVNode.tag === SuspenseComponent) {
targetVNode = null;
}
} else {
// vNode已销毁
targetVNode = null;
}
}
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
}
// 监听委托事件
function listenToNativeEvent( function listenToNativeEvent(
nativeEvtName: string, nativeEvtName: string,
delegatedElement: Element, delegatedElement: Element,
@ -37,12 +65,8 @@ function listenToNativeEvent(
const listenerSetKey = getListenerSetKey(nativeEvtName, isCapture); const listenerSetKey = getListenerSetKey(nativeEvtName, isCapture);
if (!listenerSet.has(listenerSetKey)) { if (!listenerSet.has(listenerSetKey)) {
const listener = createCustomEventListener( const listener = triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
target, target.addEventListener(nativeEvtName, listener, isCapture);
nativeEvtName,
isCapture,
);
target.addEventListener(nativeEvtName, listener, !!isCapture);
listenerSet.add(listenerSetKey); listenerSet.add(listenerSetKey);
} }
} }
@ -54,11 +78,11 @@ export function listenDelegatedEvents(dom: Element) {
return; return;
} }
dom[listeningMarker] = true; dom[listeningMarker] = true;
allDelegatedNativeEvents.forEach((eventName: string) => { allDelegatedNativeEvents.forEach((nativeEvtName: string) => {
// 委托冒泡事件 // 委托冒泡事件
listenToNativeEvent(eventName, dom, false); listenToNativeEvent(nativeEvtName, dom, false);
// 委托捕获事件 // 委托捕获事件
listenToNativeEvent(eventName, dom, true); listenToNativeEvent(nativeEvtName, dom, true);
}); });
} }
@ -86,7 +110,7 @@ function getIsCapture(horizonEventName) {
// 封装监听函数 // 封装监听函数
function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) { function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) {
return (event) => { return event => {
const customEvent = new CustomBaseEvent(horizonEventName, nativeEvtName, event, null, targetElement); const customEvent = new CustomBaseEvent(horizonEventName, nativeEvtName, event, null, targetElement);
listener(customEvent); listener(customEvent);
}; };
@ -102,19 +126,20 @@ export function listenNonDelegatedEvent(
const nativeEvtName = getNativeEvtName(horizonEventName, isCapture); const nativeEvtName = getNativeEvtName(horizonEventName, isCapture);
// 先判断是否存在老的监听事件,若存在则移除 // 先判断是否存在老的监听事件,若存在则移除
const eventToListenerMap = getEventToListenerMap(domElement); const nonDelegatedListenerMap = getNonDelegatedListenerMap(domElement);
if (eventToListenerMap.get(horizonEventName)) { const currentListener = nonDelegatedListenerMap.get(horizonEventName);
domElement.removeEventListener(nativeEvtName, eventToListenerMap.get(horizonEventName)); if (currentListener) {
domElement.removeEventListener(nativeEvtName, currentListener);
} }
if (typeof listener !== 'function') { if (typeof listener !== 'function') {
eventToListenerMap.delete(nativeEvtName); nonDelegatedListenerMap.delete(nativeEvtName);
return; return;
} }
// 为了和委托事件对外行为一致将事件对象封装成CustomBaseEvent // 为了和委托事件对外行为一致将事件对象封装成CustomBaseEvent
const wrapperListener = getWrapperListener(horizonEventName, nativeEvtName, domElement, listener); const wrapperListener = getWrapperListener(horizonEventName, nativeEvtName, domElement, listener);
// 添加新的监听 // 添加新的监听
eventToListenerMap.set(horizonEventName, wrapperListener); nonDelegatedListenerMap.set(horizonEventName, wrapperListener);
domElement.addEventListener(nativeEvtName, wrapperListener, isCapture); domElement.addEventListener(nativeEvtName, wrapperListener, isCapture);
} }

View File

@ -1,4 +1,4 @@
import type { AnyNativeEvent, ProcessingListenerList } from './types'; import type { AnyNativeEvent, ProcessingListenerList } from './Types';
import type { VNode } from '../renderer/Types'; import type { VNode } from '../renderer/Types';
import { import {
@ -34,12 +34,12 @@ function getCommonListeners(
target: null | EventTarget, target: null | EventTarget,
isCapture: boolean, isCapture: boolean,
): ProcessingListenerList { ): ProcessingListenerList {
const customEventName = getCustomEventNameWithOn(CommonEventToHorizonMap[nativeEvtName]); const horizonEvtName = getCustomEventNameWithOn(CommonEventToHorizonMap[nativeEvtName]);
if (!customEventName) { if (!horizonEvtName) {
return []; return [];
} }
// 火狐浏览器兼容。火狐浏览器下功能键将触发keypress事件 火狐下keypress的charcode有值keycode为0 // 火狐浏览器兼容。火狐浏览器下功能键将触发keypress事件 火狐下keypress的charCode有值keyCode为0
if (nativeEvtName === 'keypress' && uniqueCharCode(nativeEvent) === 0) { if (nativeEvtName === 'keypress' && uniqueCharCode(nativeEvent) === 0) {
return []; return [];
} }
@ -52,23 +52,22 @@ function getCommonListeners(
if (nativeEvtName === 'focusin') { if (nativeEvtName === 'focusin') {
nativeEvtName = 'focus'; nativeEvtName = 'focus';
} }
if (nativeEvtName === 'focusout') { if (nativeEvtName === 'focusout') {
nativeEvtName = 'blur'; nativeEvtName = 'blur';
} }
const customEvent = createCommonCustomEvent(customEventName, nativeEvtName, nativeEvent, null, target); const horizonEvent = createCommonCustomEvent(horizonEvtName, nativeEvtName, nativeEvent, null, target);
return getListenersFromTree( return getListenersFromTree(
vNode, vNode,
customEventName, horizonEvtName,
customEvent, horizonEvent,
isCapture ? EVENT_TYPE_CAPTURE : EVENT_TYPE_BUBBLE, isCapture ? EVENT_TYPE_CAPTURE : EVENT_TYPE_BUBBLE,
); );
} }
// 按顺序执行事件队列 // 按顺序执行事件队列
export function processListeners( function processListeners(processingEventsList: ProcessingListenerList): void {
processingEventsList: ProcessingListenerList
): void {
processingEventsList.forEach(eventUnitList => { processingEventsList.forEach(eventUnitList => {
let lastVNode; let lastVNode;
eventUnitList.forEach(eventUnit => { eventUnitList.forEach(eventUnit => {
@ -88,7 +87,7 @@ export function processListeners(
function getProcessListenersFacade( function getProcessListenersFacade(
nativeEvtName: string, nativeEvtName: string,
vNode: VNode, vNode: VNode | null,
nativeEvent: AnyNativeEvent, nativeEvent: AnyNativeEvent,
target, target,
isCapture: boolean isCapture: boolean
@ -150,15 +149,12 @@ function triggerHorizonEvents(
nativeEvtName: string, nativeEvtName: string,
isCapture: boolean, isCapture: boolean,
nativeEvent: AnyNativeEvent, nativeEvent: AnyNativeEvent,
vNode: null | VNode, vNode: VNode | null,
): void { ): void {
const nativeEventTarget = getEventTarget(nativeEvent); const nativeEventTarget = getEventTarget(nativeEvent);
const processingListenerList = getProcessListenersFacade(
nativeEvtName, // 获取委托事件队列
vNode, const processingListenerList = getProcessListenersFacade(nativeEvtName, vNode, nativeEvent, nativeEventTarget, isCapture);
nativeEvent,
nativeEventTarget,
isCapture);
// 处理触发的事件队列 // 处理触发的事件队列
processListeners(processingListenerList); processListeners(processingListenerList);
@ -168,6 +164,7 @@ function triggerHorizonEvents(
// 其他事件正在执行中标记 // 其他事件正在执行中标记
let isInEventsExecution = false; let isInEventsExecution = false;
// 处理委托事件入口
export function handleEventMain( export function handleEventMain(
nativeEvtName: string, nativeEvtName: string,
isCapture: boolean, isCapture: boolean,
@ -192,13 +189,7 @@ export function handleEventMain(
// 没有事件在执行,经过调度再执行事件 // 没有事件在执行,经过调度再执行事件
isInEventsExecution = true; isInEventsExecution = true;
try { try {
asyncUpdates(() => asyncUpdates(() => triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode));
triggerHorizonEvents(
nativeEvtName,
isCapture,
nativeEvent,
rootVNode,
));
} finally { } finally {
isInEventsExecution = false; isInEventsExecution = false;
if (shouldUpdateValue()) { if (shouldUpdateValue()) {

View File

@ -7,11 +7,7 @@ import {ProcessingListenerList, ListenerUnitList} from './Types';
import {CustomBaseEvent} from './customEvents/CustomBaseEvent'; import {CustomBaseEvent} from './customEvents/CustomBaseEvent';
// 返回是否应该阻止事件响应标记disabled组件不响应鼠标事件 // 返回是否应该阻止事件响应标记disabled组件不响应鼠标事件
function shouldPrevent( function shouldPrevent(eventName: string, type: string, props: Props): boolean {
name: string,
type: string,
props: Props,
): boolean {
const canPreventMouseEvents = [ const canPreventMouseEvents = [
'onClick', 'onClick',
'onClickCapture', 'onClickCapture',
@ -26,17 +22,14 @@ function shouldPrevent(
'onMouseEnter', 'onMouseEnter',
]; ];
const interActiveElements = ['button', 'input', 'select', 'textarea']; const interActiveElements = ['button', 'input', 'select', 'textarea'];
if (canPreventMouseEvents.includes(name)) { if (canPreventMouseEvents.includes(eventName)) {
return !!(props.disabled && interActiveElements.includes(type)); return !!(props.disabled && interActiveElements.includes(type));
} }
return false; return false;
} }
// 从vnode属性中获取事件listener // 从vnode属性中获取事件listener
function getListener( function getListener(vNode: VNode, eventName: string): Function | null {
vNode: VNode,
eventName: string,
): Function | null {
const realNode = vNode.realNode; const realNode = vNode.realNode;
if (realNode === null) { if (realNode === null) {
return null; return null;
@ -60,14 +53,14 @@ function getListener(
// 获取监听事件 // 获取监听事件
export function getListenersFromTree( export function getListenersFromTree(
targetVNode: VNode | null, targetVNode: VNode | null,
name: string | null, horizonEvtName: string | null,
horizonEvent: CustomBaseEvent, horizonEvent: CustomBaseEvent,
eventType: string, eventType: string,
): ProcessingListenerList { ): ProcessingListenerList {
if (!name) { if (!horizonEvtName) {
return []; return [];
} }
const captureName = name + EVENT_TYPE_CAPTURE;
const listeners: ListenerUnitList = []; const listeners: ListenerUnitList = [];
let vNode = targetVNode; let vNode = targetVNode;
@ -77,6 +70,7 @@ export function getListenersFromTree(
const {realNode, tag} = vNode; const {realNode, tag} = vNode;
if (tag === DomComponent && realNode !== null) { if (tag === DomComponent && realNode !== null) {
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_CAPTURE) { if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_CAPTURE) {
const captureName = horizonEvtName + EVENT_TYPE_CAPTURE;
const captureListener = getListener(vNode, captureName); const captureListener = getListener(vNode, captureName);
if (captureListener) { if (captureListener) {
listeners.unshift({ listeners.unshift({
@ -88,7 +82,7 @@ export function getListenersFromTree(
} }
} }
if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_BUBBLE) { if (eventType === EVENT_TYPE_ALL || eventType === EVENT_TYPE_BUBBLE) {
const bubbleListener = getListener(vNode, name); const bubbleListener = getListener(vNode, horizonEvtName);
if (bubbleListener) { if (bubbleListener) {
listeners.push({ listeners.push({
vNode, vNode,

View File

@ -1,41 +0,0 @@
import {isMounted} from '../renderer/vnode/VNodeUtils';
import {SuspenseComponent} from '../renderer/vnode/VNodeTags';
import {getNearestVNode} from '../dom/DOMInternalKeys';
import {handleEventMain} from './HorizonEventMain';
import {runDiscreteUpdates} from '../renderer/Renderer';
import {getEventTarget} from './utils';
// 触发委托事件
function triggerDelegatedEvent(
nativeEvtName: string,
isCapture: boolean,
targetDom: EventTarget,
nativeEvent,
) {
// 执行之前的调度事件
runDiscreteUpdates();
const nativeEventTarget = getEventTarget(nativeEvent);
let targetVNode = getNearestVNode(nativeEventTarget);
if (targetVNode !== null) {
if (isMounted(targetVNode)) {
if (targetVNode.tag === SuspenseComponent) {
targetVNode = null;
}
} else {
// vnode已销毁
targetVNode = null;
}
}
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
}
// 生成委托事件的监听方法
export function createCustomEventListener(
target: EventTarget,
nativeEvtName: string,
isCapture: boolean,
): EventListener {
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
}

View File

@ -69,7 +69,7 @@ export class CustomBaseEvent {
customEvtName: string | null, customEvtName: string | null,
nativeEvtName: string, nativeEvtName: string,
nativeEvt: { [propName: string]: any }, nativeEvt: { [propName: string]: any },
vNode: VNode, vNode: VNode | null,
target: null | EventTarget target: null | EventTarget
) { ) {
// 复制原生属性到自定义事件 // 复制原生属性到自定义事件

View File

@ -50,7 +50,5 @@ export function getCustomEventNameWithOn(name) {
if (!name) { if (!name) {
return ''; return '';
} }
const capitalizedEvent = name[0].toUpperCase() + name.slice(1); return 'on' + name[0].toUpperCase() + name.slice(1);
const horizonEventName = 'on' + capitalizedEvent;
return horizonEventName;
} }

View File

@ -2,14 +2,16 @@
export const ByAsync = 'BY_ASYNC'; export const ByAsync = 'BY_ASYNC';
export const BySync = 'BY_SYNC'; export const BySync = 'BY_SYNC';
export const InRender = 'IN_RENDER'; export const InRender = 'IN_RENDER';
export const InEvent = 'IN_EVENT';
type RenderMode = typeof ByAsync | typeof BySync | typeof InRender; type RenderMode = typeof ByAsync | typeof BySync | typeof InRender | typeof InEvent;
// 当前执行模式标记 // 当前执行模式标记
let executeMode = { let executeMode = {
[ByAsync]: false, [ByAsync]: false,
[BySync]: false, [BySync]: false,
[InRender]: false, [InRender]: false,
[InEvent]: false,
}; };
export function changeMode(mode: RenderMode, state = true) { export function changeMode(mode: RenderMode, state = true) {
@ -21,7 +23,7 @@ export function checkMode(mode: RenderMode) {
} }
export function isExecuting() { export function isExecuting() {
return executeMode[ByAsync] || executeMode[BySync] || executeMode[InRender]; return executeMode[ByAsync] || executeMode[BySync] || executeMode[InRender] || executeMode[InEvent];
} }
export function copyExecuteMode() { export function copyExecuteMode() {

View File

@ -9,9 +9,9 @@ import {
} from './TreeBuilder'; } from './TreeBuilder';
import { runAsyncEffects } from './submit/HookEffectHandler'; import { runAsyncEffects } from './submit/HookEffectHandler';
import { Callback, newUpdate, pushUpdate } from './UpdateHandler'; import { Callback, newUpdate, pushUpdate } from './UpdateHandler';
import { getFirstChild } from './vnode/VNodeUtils';
export { createVNode } from './vnode/VNodeCreator';
export { createVNode, createTreeRootVNode } from './vnode/VNodeCreator';
export { createPortal } from './components/CreatePortal'; export { createPortal } from './components/CreatePortal';
export { export {
asyncUpdates, asyncUpdates,

View File

@ -22,10 +22,11 @@ import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils';
import { import {
ByAsync, ByAsync,
BySync, BySync,
InRender,
InEvent,
changeMode, changeMode,
checkMode, checkMode,
copyExecuteMode, copyExecuteMode,
InRender,
isExecuting, isExecuting,
setExecuteMode setExecuteMode
} from './ExecuteMode'; } from './ExecuteMode';
@ -320,7 +321,7 @@ export function runDiscreteUpdates() {
export function asyncUpdates(fn, ...param) { export function asyncUpdates(fn, ...param) {
const preMode = copyExecuteMode(); const preMode = copyExecuteMode();
changeMode(ByAsync, true); changeMode(InEvent, true);
try { try {
return fn(...param); return fn(...param);
} finally { } finally {

View File

@ -2,7 +2,7 @@ import type { VNode } from '../Types';
import { FlagUtils } from '../vnode/VNodeFlags'; import { FlagUtils } from '../vnode/VNodeFlags';
import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType'; import { TYPE_COMMON_ELEMENT, TYPE_FRAGMENT, TYPE_PORTAL } from '../../external/JSXElementType';
import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags'; import { DomText, DomPortal, Fragment, DomComponent } from '../vnode/VNodeTags';
import {updateVNode, createVNode, createVNodeFromElement, updateVNodePath} from '../vnode/VNodeCreator'; import {updateVNode, createVNodeFromElement, updateVNodePath, createFragmentVNode, createPortalVNode, createDomTextVNode} from '../vnode/VNodeCreator';
import { import {
isSameType, isSameType,
getIteratorFn, getIteratorFn,
@ -113,7 +113,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
switch (newNodeType) { switch (newNodeType) {
case DiffCategory.TEXT_NODE: { case DiffCategory.TEXT_NODE: {
if (oldNode === null || oldNode.tag !== DomText) { if (oldNode === null || oldNode.tag !== DomText) {
resultNode = createVNode(DomText, String(newChild)); resultNode = createDomTextVNode(String(newChild));
} else { } else {
resultNode = updateVNode(oldNode, String(newChild)); resultNode = updateVNode(oldNode, String(newChild));
} }
@ -121,7 +121,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
} }
case DiffCategory.ARR_NODE: { case DiffCategory.ARR_NODE: {
if (oldNode === null || oldNode.tag !== Fragment) { if (oldNode === null || oldNode.tag !== Fragment) {
resultNode = createVNode(Fragment, null, newChild); resultNode = createFragmentVNode(null, newChild);
} else { } else {
resultNode = updateVNode(oldNode, newChild); resultNode = updateVNode(oldNode, newChild);
} }
@ -132,7 +132,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
if (newChild.type === TYPE_FRAGMENT) { if (newChild.type === TYPE_FRAGMENT) {
if (oldNode === null || oldNode.tag !== Fragment) { if (oldNode === null || oldNode.tag !== Fragment) {
const key = oldNode !== null ? oldNode.key : newChild.key; const key = oldNode !== null ? oldNode.key : newChild.key;
resultNode = createVNode(Fragment, key, newChild.props.children); resultNode = createFragmentVNode(key, newChild.props.children);
} else { } else {
resultNode = updateVNode(oldNode, newChild); resultNode = updateVNode(oldNode, newChild);
} }
@ -151,7 +151,7 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
break; break;
} else if (newChild.vtype === TYPE_PORTAL) { } else if (newChild.vtype === TYPE_PORTAL) {
if (oldNode === null || oldNode.tag !== DomPortal || oldNode.outerDom !== newChild.outerDom) { if (oldNode === null || oldNode.tag !== DomPortal || oldNode.outerDom !== newChild.outerDom) {
resultNode = createVNode(DomPortal, newChild); resultNode = createPortalVNode(newChild);
} else { } else {
resultNode = updateVNode(oldNode, newChild.children || []); resultNode = updateVNode(oldNode, newChild.children || []);
} }
@ -504,7 +504,7 @@ function diffStringNodeHandler(
deleteVNodes(parentNode, firstChildVNode.next); deleteVNodes(parentNode, firstChildVNode.next);
newTextNode.next = null; newTextNode.next = null;
} else { } else {
newTextNode = createVNode(DomText, String(newChild)); newTextNode = createDomTextVNode(String(newChild));
deleteVNodes(parentNode, firstChildVNode); deleteVNodes(parentNode, firstChildVNode);
} }
@ -562,7 +562,7 @@ function diffObjectNodeHandler(
if (resultNode === null) { if (resultNode === null) {
// 新建 // 新建
if (newChild.type === TYPE_FRAGMENT) { if (newChild.type === TYPE_FRAGMENT) {
resultNode = createVNode(Fragment, newChild.key, newChild.props.children); resultNode = createFragmentVNode(newChild.key, newChild.props.children);
} else { } else {
resultNode = createVNodeFromElement(newChild); resultNode = createVNodeFromElement(newChild);
resultNode.ref = newChild.ref; resultNode.ref = newChild.ref;
@ -580,7 +580,7 @@ function diffObjectNodeHandler(
} }
if (resultNode === null) { if (resultNode === null) {
// 新建 // 新建
resultNode = createVNode(DomPortal, newChild); resultNode = createPortalVNode(newChild);
} }
} }

View File

@ -1,14 +1,13 @@
import type {VNode} from '../Types'; import type {VNode} from '../Types';
import {mergeDefaultProps} from './LazyComponent'; import {mergeDefaultProps} from './LazyComponent';
import {updateVNode, createVNode, onlyUpdateChildVNodes, updateVNodePath} from '../vnode/VNodeCreator'; import {updateVNode, onlyUpdateChildVNodes, updateVNodePath, createFragmentVNode, createUndeterminedVNode} from '../vnode/VNodeCreator';
import {shallowCompare} from '../utils/compare'; import {shallowCompare} from '../utils/compare';
import { import {
TYPE_FRAGMENT, TYPE_FRAGMENT,
TYPE_PROFILER, TYPE_PROFILER,
TYPE_STRICT_MODE, TYPE_STRICT_MODE,
} from '../../external/JSXElementType'; } from '../../external/JSXElementType';
import {Fragment} from '../vnode/VNodeTags';
export function bubbleRender() {} export function bubbleRender() {}
@ -24,9 +23,9 @@ export function captureMemoComponent(
let newChild = null; let newChild = null;
const type = Component.type; const type = Component.type;
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
newChild = createVNode(Fragment, null, newProps.children); newChild = createFragmentVNode(null, newProps.children);
} else { } else {
newChild = createVNode('props', type, null, newProps, processing); newChild = createUndeterminedVNode(type, null, newProps);
} }
newChild.parent = processing; newChild.parent = processing;
newChild.ref = processing.ref; newChild.ref = processing.ref;

View File

@ -1,12 +1,11 @@
import type {VNode, PromiseType} from '../Types'; import type {VNode, PromiseType} from '../Types';
import {FlagUtils, Interrupted} from '../vnode/VNodeFlags'; import {FlagUtils, Interrupted} from '../vnode/VNodeFlags';
import {createVNode, onlyUpdateChildVNodes, updateVNode, updateVNodePath} from '../vnode/VNodeCreator'; import {onlyUpdateChildVNodes, updateVNode, updateVNodePath, createFragmentVNode} from '../vnode/VNodeCreator';
import { import {
ClassComponent, ClassComponent,
IncompleteClassComponent, IncompleteClassComponent,
SuspenseComponent, SuspenseComponent,
Fragment,
} from '../vnode/VNodeTags'; } from '../vnode/VNodeTags';
import {pushForceUpdate} from '../UpdateHandler'; import {pushForceUpdate} from '../UpdateHandler';
import {launchUpdateFromVNode, tryRenderFromRoot} from '../TreeBuilder'; import {launchUpdateFromVNode, tryRenderFromRoot} from '../TreeBuilder';
@ -31,12 +30,12 @@ function createFallback(processing: VNode, fallbackChildren) {
if (oldFallbackFragment !== null) { if (oldFallbackFragment !== null) {
fallbackFragment = updateVNode(oldFallbackFragment, fallbackChildren); fallbackFragment = updateVNode(oldFallbackFragment, fallbackChildren);
} else { } else {
fallbackFragment = createVNode(Fragment, null, fallbackChildren); fallbackFragment = createFragmentVNode(null, fallbackChildren);
FlagUtils.markAddition(fallbackFragment); FlagUtils.markAddition(fallbackFragment);
} }
} else { } else {
// 创建 // 创建
fallbackFragment = createVNode(Fragment, null, fallbackChildren); fallbackFragment = createFragmentVNode(null, fallbackChildren);
} }
processing.child = childFragment; processing.child = childFragment;
@ -72,7 +71,7 @@ function createSuspenseChildren(processing: VNode, newChildren) {
// SuspenseComponent 中使用 // SuspenseComponent 中使用
processing.suspenseChildStatus = SuspenseChildStatus.ShowChild; processing.suspenseChildStatus = SuspenseChildStatus.ShowChild;
} else { } else {
childFragment = createVNode(Fragment, null, newChildren); childFragment = createFragmentVNode(null, newChildren);
} }
childFragment.parent = processing; childFragment.parent = processing;

View File

@ -87,50 +87,49 @@ export function updateVNode(vNode: VNode, vNodeProps?: any): VNode {
function getVNodeTag(type: any) { function getVNodeTag(type: any) {
let vNodeTag = ClsOrFunComponent; let vNodeTag = ClsOrFunComponent;
let isLazy = false; let isLazy = false;
const componentType = typeof type;
if (typeof type === 'function') { if (componentType === 'function') {
if (isClassComponent(type)) { if (isClassComponent(type)) {
vNodeTag = ClassComponent; vNodeTag = ClassComponent;
} }
} else if (typeof type === 'string') { } else if (componentType === 'string') {
vNodeTag = DomComponent; vNodeTag = DomComponent;
} else if (type === TYPE_SUSPENSE) { } else if (type === TYPE_SUSPENSE) {
vNodeTag = SuspenseComponent; vNodeTag = SuspenseComponent;
} else if (typeof type === 'object' && type !== null && typeMap[type.vtype]) { } else if (componentType === 'object' && type !== null && typeMap[type.vtype]) {
vNodeTag = typeMap[type.vtype]; vNodeTag = typeMap[type.vtype];
isLazy = type.vtype === TYPE_LAZY; isLazy = type.vtype === TYPE_LAZY;
} else { } else {
throw Error(`Component type is invalid, got: ${type == null ? type : typeof type}`); throw Error(`Component type is invalid, got: ${type == null ? type : componentType}`);
} }
return { vNodeTag, isLazy }; return { vNodeTag, isLazy };
} }
export function createVNode(tag: VNodeTag | string, ...secondArg) { export function createFragmentVNode(fragmentKey, fragmentProps) {
let vNode = null; const vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps);
switch (tag) {
case Fragment:
const [fragmentKey, fragmentProps] = secondArg;
vNode = newVirtualNode(Fragment, fragmentKey, fragmentProps);
vNode.shouldUpdate = true; vNode.shouldUpdate = true;
break; return vNode;
case DomText: }
const content = secondArg[0];
vNode = newVirtualNode(DomText, null, content); export function createDomTextVNode(content) {
const vNode = newVirtualNode(DomText, null, content);
vNode.shouldUpdate = true; vNode.shouldUpdate = true;
break; return vNode;
case DomPortal: }
const portal = secondArg[0];
export function createPortalVNode(portal) {
const children = portal.children ?? []; const children = portal.children ?? [];
vNode = newVirtualNode(DomPortal, portal.key, children); const vNode = newVirtualNode(DomPortal, portal.key, children);
vNode.shouldUpdate = true; vNode.shouldUpdate = true;
vNode.outerDom = portal.outerDom; vNode.outerDom = portal.outerDom;
break; return vNode;
case 'props': }
const [type, key, props] = secondArg;
export function createUndeterminedVNode(type, key, props) {
const { vNodeTag, isLazy } = getVNodeTag(type); const { vNodeTag, isLazy } = getVNodeTag(type);
vNode = newVirtualNode(vNodeTag, key, props); const vNode = newVirtualNode(vNodeTag, key, props);
vNode.type = type; vNode.type = type;
vNode.shouldUpdate = true; vNode.shouldUpdate = true;
@ -139,7 +138,20 @@ export function createVNode(tag: VNodeTag | string, ...secondArg) {
if (isLazy) { if (isLazy) {
vNode.lazyType = type; vNode.lazyType = type;
} }
break; return vNode;
}
export function createTreeRootVNode(container) {
const vNode = newVirtualNode(TreeRoot, null, null, container);
vNode.path.push(0);
createUpdateArray(vNode);
return vNode;
}
// TODO: 暂时保留给测试用例使用,后续修改测试用例
export function createVNode(tag: VNodeTag | string, ...secondArg) {
let vNode = null;
switch (tag) {
case TreeRoot: case TreeRoot:
// 创建treeRoot // 创建treeRoot
vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]); vNode = newVirtualNode(TreeRoot, null, null, secondArg[0]);
@ -162,9 +174,9 @@ export function createVNodeFromElement(element: JSXElement): VNode {
const props = element.props; const props = element.props;
if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) { if (type === TYPE_STRICT_MODE || type === TYPE_FRAGMENT || type === TYPE_PROFILER) {
return createVNode(Fragment, key, props.children); return createFragmentVNode(key, props.children);
} else { } else {
return createVNode('props', type, key, props); return createUndeterminedVNode(type, key, props);
} }
} }