Match-id-87d7a306856b74030f13b40cb209b873d055d41e
This commit is contained in:
parent
fa55d306c2
commit
2d97a19610
|
@ -10,30 +10,6 @@ import {findDOMByClassInst} from '../renderer/vnode/VNodeUtils';
|
|||
import {TreeRoot} from '../renderer/vnode/VNodeTags';
|
||||
import {Callback} from '../renderer/UpdateHandler';
|
||||
|
||||
function executeRender(
|
||||
children: any,
|
||||
container: Container,
|
||||
callback?: Callback,
|
||||
) {
|
||||
let treeRoot = container._treeRoot;
|
||||
|
||||
if (!treeRoot) {
|
||||
treeRoot = createRoot(children, container, callback);
|
||||
} else { // container被render过
|
||||
if (typeof callback === 'function') {
|
||||
const cb = callback;
|
||||
callback = function () {
|
||||
const instance = getFirstCustomDom(treeRoot);
|
||||
cb.call(instance);
|
||||
};
|
||||
}
|
||||
// 执行更新操作
|
||||
startUpdate(children, treeRoot, callback);
|
||||
}
|
||||
|
||||
return getFirstCustomDom(treeRoot);
|
||||
}
|
||||
|
||||
function createRoot(children: any, container: Container, callback?: Callback) {
|
||||
// 清空容器
|
||||
let child = container.lastChild;
|
||||
|
@ -66,8 +42,32 @@ function createRoot(children: any, container: Container, callback?: Callback) {
|
|||
return treeRoot;
|
||||
}
|
||||
|
||||
function executeRender(
|
||||
children: any,
|
||||
container: Container,
|
||||
callback?: Callback,
|
||||
) {
|
||||
let treeRoot = container._treeRoot;
|
||||
|
||||
if (!treeRoot) {
|
||||
treeRoot = createRoot(children, container, callback);
|
||||
} else { // container被render过
|
||||
if (typeof callback === 'function') {
|
||||
const cb = callback;
|
||||
callback = function () {
|
||||
const instance = getFirstCustomDom(treeRoot);
|
||||
cb.call(instance);
|
||||
};
|
||||
}
|
||||
// 执行更新操作
|
||||
startUpdate(children, treeRoot, callback);
|
||||
}
|
||||
|
||||
return getFirstCustomDom(treeRoot);
|
||||
}
|
||||
|
||||
function findDOMNode(domOrEle: Element): null | Element | Text {
|
||||
if (domOrEle == null) {
|
||||
if (!domOrEle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ export function getNearestVNode(dom: Node): null | VNode {
|
|||
}
|
||||
|
||||
// 获取 vNode 上的属性相关信息
|
||||
export function getVNodeProps(dom: Element | Text): Props {
|
||||
export function getVNodeProps(dom: Element | Text): Props | null{
|
||||
return dom[internalKeys.props] || null;
|
||||
}
|
||||
|
||||
|
@ -93,7 +93,8 @@ export function getEventListeners(dom: EventTarget): Set<string> {
|
|||
export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> {
|
||||
let eventsMap = target[internalKeys.nonDelegatedEvents];
|
||||
if (!eventsMap) {
|
||||
eventsMap = target[internalKeys.nonDelegatedEvents] = new Map();
|
||||
eventsMap = new Map();
|
||||
target[internalKeys.nonDelegatedEvents] = new Map();
|
||||
}
|
||||
return eventsMap;
|
||||
}
|
||||
|
|
|
@ -5,13 +5,13 @@ import {
|
|||
import {
|
||||
createDom,
|
||||
} from './utils/DomCreator';
|
||||
import {getSelectionInfo, resetSelectionRange, selectionData} from './SelectionRangeHandler';
|
||||
import {isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus} from './utils/Common';
|
||||
import {NSS} from './utils/DomCreator';
|
||||
import {adjustStyleValue} from './DOMPropertiesHandler/StyleHandler';
|
||||
import { getSelectionInfo, resetSelectionRange, selectionData } from './SelectionRangeHandler';
|
||||
import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
|
||||
import { NSS } from './utils/DomCreator';
|
||||
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||
|
||||
import {listenDelegatedEvents} from '../event/EventBinding';
|
||||
import type {VNode} from '../renderer/Types';
|
||||
import { listenDelegatedEvents } from '../event/EventBinding';
|
||||
import type { VNode } from '../renderer/Types';
|
||||
import {
|
||||
setInitValue,
|
||||
getPropsWithoutValue,
|
||||
|
@ -21,10 +21,10 @@ import {
|
|||
compareProps,
|
||||
setDomProps, updateDomProps
|
||||
} from './DOMPropertiesHandler/DOMPropertiesHandler';
|
||||
import {isNativeElement, validateProps} from './validators/ValidateProps';
|
||||
import {watchValueChange} from './valueHandler/ValueChangeHandler';
|
||||
import {DomComponent, DomText} from '../renderer/vnode/VNodeTags';
|
||||
import {updateCommonProp} from './DOMPropertiesHandler/UpdateCommonProp';
|
||||
import { isNativeElement, validateProps } from './validators/ValidateProps';
|
||||
import { watchValueChange } from './valueHandler/ValueChangeHandler';
|
||||
import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
|
||||
import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
|
||||
|
||||
export type Props = {
|
||||
autoFocus?: boolean;
|
||||
|
@ -55,13 +55,7 @@ function getChildNS(parentNS: string | null, tagName: string): string {
|
|||
|
||||
// 获取容器
|
||||
export function getNSCtx(dom: Container, parentNS: string, type: string): string {
|
||||
let namespace;
|
||||
if (dom) {
|
||||
namespace = getChildNS(dom.namespaceURI ?? null, dom.nodeName);
|
||||
} else {
|
||||
namespace = getChildNS(parentNS, type);
|
||||
}
|
||||
return namespace;
|
||||
return dom ? getChildNS(dom.namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
|
||||
}
|
||||
|
||||
export function prepareForSubmit(): void {
|
||||
|
@ -156,7 +150,7 @@ export function newTextDom(
|
|||
// 提交vNode的类型为Component或者Text的更新
|
||||
export function submitDomUpdate(tag: string, vNode: VNode) {
|
||||
const newProps = vNode.props;
|
||||
const element: Element = vNode.realNode;
|
||||
const element: Element | null = vNode.realNode;
|
||||
|
||||
if (tag === DomComponent) {
|
||||
// DomComponent类型
|
||||
|
@ -179,8 +173,10 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
|
|||
}
|
||||
}
|
||||
} else if (tag === DomText) {
|
||||
// text类型
|
||||
element.textContent = newProps;
|
||||
if (element != null) {
|
||||
// text类型
|
||||
element.textContent = newProps;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,6 +8,27 @@ import {
|
|||
} from '../../event/EventBinding';
|
||||
import { isEventProp, isNativeElement } from '../validators/ValidateProps';
|
||||
|
||||
function updateOneProp(dom, propName, propVal, isNativeTag, isInit?: boolean) {
|
||||
if (propName === 'style') {
|
||||
setStyles(dom, propVal);
|
||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||
dom.innerHTML = propVal.__html;
|
||||
} else if (propName === 'children') { // 只处理纯文本子节点,其他children在VNode树中处理
|
||||
if (typeof propVal === 'string' || typeof propVal === 'number') {
|
||||
dom.textContent = String(propVal);
|
||||
}
|
||||
} else if (isEventProp(propName)) {
|
||||
// 事件监听属性处理
|
||||
if (!allDelegatedHorizonEvents.has(propName)) {
|
||||
listenNonDelegatedEvent(propName, dom, propVal);
|
||||
}
|
||||
} else {
|
||||
if (!isInit || (isInit && propVal != null)) {
|
||||
updateCommonProp(dom, propName, propVal, isNativeTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 初始化DOM属性
|
||||
export function setDomProps(
|
||||
tagName: string,
|
||||
|
@ -38,27 +59,6 @@ export function updateDomProps(
|
|||
}
|
||||
}
|
||||
|
||||
function updateOneProp(dom, propName, propVal, isNativeTag, isInit?: boolean) {
|
||||
if (propName === 'style') {
|
||||
setStyles(dom, propVal);
|
||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||
dom.innerHTML = propVal.__html;
|
||||
} else if (propName === 'children') { // 只处理纯文本子节点,其他children在VNode树中处理
|
||||
if (typeof propVal === 'string' || typeof propVal === 'number') {
|
||||
dom.textContent = String(propVal);
|
||||
}
|
||||
} else if (isEventProp(propName)) {
|
||||
// 事件监听属性处理
|
||||
if (!allDelegatedHorizonEvents.has(propName)) {
|
||||
listenNonDelegatedEvent(propName, dom, propVal);
|
||||
}
|
||||
} else {
|
||||
if (!isInit || (isInit && propVal != null)) {
|
||||
updateCommonProp(dom, propName, propVal, isNativeTag);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 找出两个 DOM 属性的差别,生成需要更新的属性集合
|
||||
export function compareProps(
|
||||
oldProps: Object,
|
||||
|
|
|
@ -122,7 +122,9 @@ function getProcessListenersFacade(
|
|||
));
|
||||
}
|
||||
|
||||
if (nativeEvtName === 'compositionend' || nativeEvtName === 'compositionstart' || nativeEvtName === 'compositionupdate') {
|
||||
if (nativeEvtName === 'compositionend' ||
|
||||
nativeEvtName === 'compositionstart' ||
|
||||
nativeEvtName === 'compositionupdate') {
|
||||
processingListenerList = processingListenerList.concat(getCompositionListeners(
|
||||
nativeEvtName,
|
||||
nativeEvent,
|
||||
|
@ -183,13 +185,14 @@ export function handleEventMain(
|
|||
|
||||
// 有事件正在执行,同步执行事件
|
||||
if (isInEventsExecution) {
|
||||
return triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
|
||||
triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
|
||||
return;
|
||||
}
|
||||
|
||||
// 没有事件在执行,经过调度再执行事件
|
||||
isInEventsExecution = true;
|
||||
try {
|
||||
return asyncUpdates(() =>
|
||||
asyncUpdates(() =>
|
||||
triggerHorizonEvents(
|
||||
nativeEvtName,
|
||||
isCapture,
|
||||
|
|
|
@ -5,15 +5,6 @@ import {handleEventMain} from './HorizonEventMain';
|
|||
import {runDiscreteUpdates} from '../renderer/Renderer';
|
||||
import {getEventTarget} from './utils';
|
||||
|
||||
// 生成委托事件的监听方法
|
||||
export function createCustomEventListener(
|
||||
target: EventTarget,
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
): EventListener {
|
||||
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
|
||||
}
|
||||
|
||||
// 触发委托事件
|
||||
function triggerDelegatedEvent(
|
||||
nativeEvtName: string,
|
||||
|
@ -39,3 +30,12 @@ function triggerDelegatedEvent(
|
|||
}
|
||||
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
|
||||
}
|
||||
|
||||
// 生成委托事件的监听方法
|
||||
export function createCustomEventListener(
|
||||
target: EventTarget,
|
||||
nativeEvtName: string,
|
||||
isCapture: boolean,
|
||||
): EventListener {
|
||||
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
|
||||
}
|
||||
|
|
|
@ -4,6 +4,48 @@
|
|||
|
||||
import {VNode} from '../../renderer/Types';
|
||||
|
||||
// 从原生事件中复制属性到自定义事件中
|
||||
function extendAttribute(target, source) {
|
||||
const attributes = [
|
||||
// AnimationEvent
|
||||
'animationName', 'elapsedTime', 'pseudoElement',
|
||||
// CompositionEvent、InputEvent
|
||||
'data',
|
||||
// DragEvent
|
||||
'dataTransfer',
|
||||
// FocusEvent
|
||||
'relatedTarget',
|
||||
// KeyboardEvent
|
||||
'key', 'keyCode', 'charCode', 'code', 'location', 'ctrlKey', 'shiftKey',
|
||||
'altKey', 'metaKey', 'repeat', 'locale', 'getModifierState', 'clipboardData',
|
||||
// MouseEvent
|
||||
'button', 'buttons', 'clientX', 'clientY', 'movementX', 'movementY',
|
||||
'pageX', 'pageY', 'screenX', 'screenY', 'currentTarget',
|
||||
// PointerEvent
|
||||
'pointerId', 'width', 'height', 'pressure', 'tangentialPressure',
|
||||
'tiltX', 'tiltY', 'twist', 'pointerType', 'isPrimary',
|
||||
// TouchEvent
|
||||
'touches', 'targetTouches', 'changedTouches',
|
||||
// TransitionEvent
|
||||
'propertyName',
|
||||
// UIEvent
|
||||
'view', 'detail',
|
||||
// WheelEvent
|
||||
'deltaX', 'deltaY', 'deltaZ', 'deltaMode',
|
||||
];
|
||||
|
||||
attributes.forEach(attr => {
|
||||
if (typeof source[attr] !== 'undefined') {
|
||||
if (typeof source[attr] === 'function') {
|
||||
target[attr] = function() {
|
||||
return source[attr].apply(source, arguments);
|
||||
};
|
||||
} else {
|
||||
target[attr] = source[attr];
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
export class CustomBaseEvent {
|
||||
|
||||
data: string;
|
||||
|
@ -79,46 +121,3 @@ export class CustomBaseEvent {
|
|||
this.isPropagationStopped = () => true;
|
||||
}
|
||||
}
|
||||
|
||||
// 从原生事件中复制属性到自定义事件中
|
||||
function extendAttribute(target, source) {
|
||||
const attributes = [
|
||||
// AnimationEvent
|
||||
'animationName', 'elapsedTime', 'pseudoElement',
|
||||
// CompositionEvent、InputEvent
|
||||
'data',
|
||||
// DragEvent
|
||||
'dataTransfer',
|
||||
// FocusEvent
|
||||
'relatedTarget',
|
||||
// KeyboardEvent
|
||||
'key', 'keyCode', 'charCode', 'code', 'location', 'ctrlKey', 'shiftKey',
|
||||
'altKey', 'metaKey', 'repeat', 'locale', 'getModifierState', 'clipboardData',
|
||||
// MouseEvent
|
||||
'button', 'buttons', 'clientX', 'clientY', 'movementX', 'movementY',
|
||||
'pageX', 'pageY', 'screenX', 'screenY', 'currentTarget',
|
||||
// PointerEvent
|
||||
'pointerId', 'width', 'height', 'pressure', 'tangentialPressure',
|
||||
'tiltX', 'tiltY', 'twist', 'pointerType', 'isPrimary',
|
||||
// TouchEvent
|
||||
'touches', 'targetTouches', 'changedTouches',
|
||||
// TransitionEvent
|
||||
'propertyName',
|
||||
// UIEvent
|
||||
'view', 'detail',
|
||||
// WheelEvent
|
||||
'deltaX', 'deltaY', 'deltaZ', 'deltaMode',
|
||||
];
|
||||
|
||||
attributes.forEach(attr => {
|
||||
if (typeof source[attr] !== 'undefined') {
|
||||
if (typeof source[attr] === 'function') {
|
||||
target[attr] = function() {
|
||||
return source[attr].apply(source, arguments);
|
||||
};
|
||||
} else {
|
||||
target[attr] = source[attr];
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ export class CustomKeyboardEvent extends CustomBaseEvent {
|
|||
super(customEvtName, nativeEvtName, nativeEvt, vNode, target);
|
||||
this.key = getKey(nativeEvt);
|
||||
this.charCode = nativeEvtName === 'keypress' ? uniqueCharCode(nativeEvt) : 0;
|
||||
this.keyCode = (nativeEvtName === 'keydown' || nativeEvtName === 'keyup') ? nativeEvt.keyCode : 0;
|
||||
this.keyCode = nativeEvtName === 'keydown' || nativeEvtName === 'keyup' ? nativeEvt.keyCode : 0;
|
||||
this.which = this.charCode || this.keyCode;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ const SPACE_CHAR = String.fromCharCode(CHAR_CODE_SPACE);
|
|||
function getInputCharsByNative(
|
||||
eventName: string,
|
||||
nativeEvent: any,
|
||||
): string | void {
|
||||
): string | null | void {
|
||||
if (eventName === 'compositionend') {
|
||||
return (nativeEvent.detail && nativeEvent.detail.data) || null;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ const horizonEventName = 'onSelect'
|
|||
|
||||
let currentElement = null;
|
||||
let currentVNode = null;
|
||||
let lastSelection = null;
|
||||
let lastSelection: Selection | null = null;
|
||||
|
||||
function initTargetCache(dom, vNode) {
|
||||
if (isTextInputElement(dom) || dom.contentEditable === 'true') {
|
||||
|
@ -85,7 +85,7 @@ export function getListeners(
|
|||
target: null | EventTarget,
|
||||
): ProcessingListenerList {
|
||||
const targetNode = vNode ? getDom(vNode) : window;
|
||||
let eventUnitList = [];
|
||||
let eventUnitList: ProcessingListenerList = [];
|
||||
switch (name) {
|
||||
case 'focusin':
|
||||
initTargetCache(targetNode, vNode);
|
||||
|
|
|
@ -10,7 +10,18 @@ import {
|
|||
cacheOldCtx,
|
||||
} from '../components/context/CompatibleContext';
|
||||
|
||||
export function captureRender(processing: VNode): Array<VNode> | null {
|
||||
function captureIncompleteClassComponent(processing, Component, nextProps) {
|
||||
processing.tag = ClassComponent;
|
||||
|
||||
const hasOldContext = isOldProvider(Component);
|
||||
cacheOldCtx(processing, hasOldContext);
|
||||
|
||||
resetDepContexts(processing);
|
||||
|
||||
return getIncompleteClassComponent(Component, processing, nextProps);
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
const Component = processing.type;
|
||||
const unresolvedProps = processing.props;
|
||||
const resolvedProps =
|
||||
|
@ -28,14 +39,3 @@ export function bubbleRender(processing: VNode) {
|
|||
resetOldCtx(processing);
|
||||
}
|
||||
}
|
||||
|
||||
function captureIncompleteClassComponent(processing, Component, nextProps) {
|
||||
processing.tag = ClassComponent;
|
||||
|
||||
const hasOldContext = isOldProvider(Component);
|
||||
cacheOldCtx(processing, hasOldContext);
|
||||
|
||||
resetDepContexts(processing);
|
||||
|
||||
return getIncompleteClassComponent(Component, processing, nextProps);
|
||||
}
|
||||
|
|
|
@ -13,10 +13,6 @@ import { captureFunctionComponent } from './FunctionComponent';
|
|||
import { captureClassComponent } from './ClassComponent';
|
||||
import { captureMemoComponent } from './MemoComponent';
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
||||
}
|
||||
|
||||
export function bubbleRender() { }
|
||||
|
||||
const LazyRendererMap = {
|
||||
|
@ -26,6 +22,20 @@ const LazyRendererMap = {
|
|||
[MemoComponent]: captureMemoComponent,
|
||||
};
|
||||
|
||||
export function mergeDefaultProps(Component: any, props: object): object {
|
||||
if (Component && Component.defaultProps) {
|
||||
const clonedProps = { ...props };
|
||||
const defaultProps = Component.defaultProps;
|
||||
Object.keys(defaultProps).forEach(key => {
|
||||
if (clonedProps[key] === undefined) {
|
||||
clonedProps[key] = defaultProps[key];
|
||||
}
|
||||
});
|
||||
return clonedProps;
|
||||
}
|
||||
return props;
|
||||
}
|
||||
|
||||
function captureLazyComponent(
|
||||
processing,
|
||||
lazyComponent,
|
||||
|
@ -43,7 +53,8 @@ function captureLazyComponent(
|
|||
// 加载得到的Component存在type中
|
||||
processing.type = Component;
|
||||
|
||||
const lazyVNodeTag = processing.tag = getLazyVNodeTag(Component);
|
||||
const lazyVNodeTag = getLazyVNodeTag(Component);
|
||||
processing.tag = getLazyVNodeTag(Component);
|
||||
const lazyVNodeProps = mergeDefaultProps(Component, processing.props);
|
||||
|
||||
const lazyRender = LazyRendererMap[lazyVNodeTag];
|
||||
|
@ -68,16 +79,6 @@ function captureLazyComponent(
|
|||
}
|
||||
}
|
||||
|
||||
export function mergeDefaultProps(Component: any, props: object): object {
|
||||
if (Component && Component.defaultProps) {
|
||||
const clonedProps = { ...props };
|
||||
const defaultProps = Component.defaultProps;
|
||||
Object.keys(defaultProps).forEach(key => {
|
||||
if (clonedProps[key] === undefined) {
|
||||
clonedProps[key] = defaultProps[key];
|
||||
}
|
||||
});
|
||||
return clonedProps;
|
||||
}
|
||||
return props;
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
||||
}
|
||||
|
|
|
@ -19,107 +19,6 @@ export enum SuspenseChildStatus {
|
|||
ShowFallback = 'showFallback',
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null {
|
||||
if (
|
||||
!processing.isCreated &&
|
||||
processing.oldProps === processing.props &&
|
||||
!getContextChangeCtx() &&
|
||||
!shouldUpdate
|
||||
) {
|
||||
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback) {
|
||||
// 当显示fallback时,suspense的子组件要更新
|
||||
return updateFallback(processing);
|
||||
}
|
||||
return onlyUpdateChildVNodes(processing);
|
||||
}
|
||||
|
||||
return captureSuspenseComponent(processing);
|
||||
}
|
||||
|
||||
function updateFallback(processing: VNode): Array<VNode> | VNode | null {
|
||||
const childFragment: VNode = processing.child;
|
||||
|
||||
if (childFragment.childShouldUpdate) {
|
||||
if (processing.promiseResolve) {
|
||||
// promise已完成,展示promise返回的新节点
|
||||
return captureSuspenseComponent(processing);
|
||||
} else {
|
||||
// promise未完成,继续显示fallback,不需要继续刷新子节点
|
||||
const fallbackFragment: VNode = processing.child.next;
|
||||
childFragment.childShouldUpdate = false;
|
||||
fallbackFragment.childShouldUpdate = false;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
const children = onlyUpdateChildVNodes(processing);
|
||||
|
||||
if (children !== null) {
|
||||
// child不需要更新,跳过child处理fallback
|
||||
return children[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback
|
||||
|| (!processing.isCreated && processing.oldSuspenseChildStatus === SuspenseChildStatus.ShowFallback)
|
||||
) {
|
||||
FlagUtils.markUpdate(processing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function captureSuspenseComponent(processing: VNode) {
|
||||
const nextProps = processing.props;
|
||||
|
||||
// suspense被捕获后需要展示fallback
|
||||
const showFallback = processing.suspenseDidCapture;
|
||||
|
||||
if (showFallback) {
|
||||
processing.suspenseDidCapture = false;
|
||||
const nextFallbackChildren = nextProps.fallback;
|
||||
return createFallback(processing, nextFallbackChildren);
|
||||
} else {
|
||||
const newChildren = nextProps.children;
|
||||
return createSuspenseChildren(processing, newChildren);
|
||||
}
|
||||
}
|
||||
|
||||
// 创建子节点
|
||||
function createSuspenseChildren(processing: VNode, newChildren) {
|
||||
let childFragment: VNode;
|
||||
if (!processing.isCreated) {
|
||||
const oldChildFragment: VNode = processing.child;
|
||||
const oldFallbackFragment: VNode | null = oldChildFragment.next;
|
||||
|
||||
childFragment = updateVNode(oldChildFragment);
|
||||
childFragment.next = null;
|
||||
// 将Suspense新的子参数传给子Fragment
|
||||
childFragment.props = processing.props.children;
|
||||
childFragment.shouldUpdate = true;
|
||||
|
||||
// 删除fallback
|
||||
if (oldFallbackFragment !== null) {
|
||||
FlagUtils.setDeletion(oldFallbackFragment);
|
||||
processing.dirtyNodes = [oldFallbackFragment];
|
||||
}
|
||||
// SuspenseComponent 中使用
|
||||
processing.suspenseChildStatus = SuspenseChildStatus.ShowChild;
|
||||
} else {
|
||||
childFragment = createVNode(Fragment, null, newChildren);
|
||||
}
|
||||
|
||||
childFragment.parent = processing;
|
||||
childFragment.cIndex = 0;
|
||||
updateVNodePath(childFragment);
|
||||
processing.child = childFragment;
|
||||
processing.promiseResolve = false;
|
||||
return processing.child;
|
||||
}
|
||||
|
||||
// 创建fallback子节点
|
||||
function createFallback(processing: VNode, fallbackChildren) {
|
||||
const childFragment: VNode = processing.child;
|
||||
|
@ -152,13 +51,118 @@ function createFallback(processing: VNode, fallbackChildren) {
|
|||
return fallbackFragment;
|
||||
}
|
||||
|
||||
// 创建子节点
|
||||
function createSuspenseChildren(processing: VNode, newChildren) {
|
||||
let childFragment: VNode;
|
||||
if (!processing.isCreated) {
|
||||
const oldChildFragment: VNode = processing.child;
|
||||
const oldFallbackFragment: VNode | null = oldChildFragment.next;
|
||||
|
||||
childFragment = updateVNode(oldChildFragment);
|
||||
childFragment.next = null;
|
||||
// 将Suspense新的子参数传给子Fragment
|
||||
childFragment.props = processing.props.children;
|
||||
childFragment.shouldUpdate = true;
|
||||
|
||||
// 删除fallback
|
||||
if (oldFallbackFragment !== null) {
|
||||
FlagUtils.setDeletion(oldFallbackFragment);
|
||||
processing.dirtyNodes = [oldFallbackFragment];
|
||||
}
|
||||
// SuspenseComponent 中使用
|
||||
processing.suspenseChildStatus = SuspenseChildStatus.ShowChild;
|
||||
} else {
|
||||
childFragment = createVNode(Fragment, null, newChildren);
|
||||
}
|
||||
|
||||
childFragment.parent = processing;
|
||||
childFragment.cIndex = 0;
|
||||
updateVNodePath(childFragment);
|
||||
processing.child = childFragment;
|
||||
processing.promiseResolve = false;
|
||||
return processing.child;
|
||||
}
|
||||
|
||||
export function captureSuspenseComponent(processing: VNode) {
|
||||
const nextProps = processing.props;
|
||||
|
||||
// suspense被捕获后需要展示fallback
|
||||
const showFallback = processing.suspenseDidCapture;
|
||||
|
||||
if (showFallback) {
|
||||
processing.suspenseDidCapture = false;
|
||||
const nextFallbackChildren = nextProps.fallback;
|
||||
return createFallback(processing, nextFallbackChildren);
|
||||
} else {
|
||||
const newChildren = nextProps.children;
|
||||
return createSuspenseChildren(processing, newChildren);
|
||||
}
|
||||
}
|
||||
|
||||
function updateFallback(processing: VNode): Array<VNode> | VNode | null {
|
||||
const childFragment: VNode | null= processing.child;
|
||||
|
||||
if (childFragment?.childShouldUpdate) {
|
||||
if (processing.promiseResolve) {
|
||||
// promise已完成,展示promise返回的新节点
|
||||
return captureSuspenseComponent(processing);
|
||||
} else {
|
||||
// promise未完成,继续显示fallback,不需要继续刷新子节点
|
||||
const fallbackFragment: VNode = processing.child.next;
|
||||
childFragment.childShouldUpdate = false;
|
||||
fallbackFragment.childShouldUpdate = false;
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
const children = onlyUpdateChildVNodes(processing);
|
||||
|
||||
if (children !== null) {
|
||||
// child不需要更新,跳过child处理fallback
|
||||
return children[1];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null {
|
||||
if (
|
||||
!processing.isCreated &&
|
||||
processing.oldProps === processing.props &&
|
||||
!getContextChangeCtx() &&
|
||||
!shouldUpdate
|
||||
) {
|
||||
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback) {
|
||||
// 当显示fallback时,suspense的子组件要更新
|
||||
return updateFallback(processing);
|
||||
}
|
||||
return onlyUpdateChildVNodes(processing);
|
||||
}
|
||||
|
||||
return captureSuspenseComponent(processing);
|
||||
}
|
||||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
if (processing.suspenseChildStatus === SuspenseChildStatus.ShowFallback
|
||||
|| (!processing.isCreated && processing.oldSuspenseChildStatus === SuspenseChildStatus.ShowFallback)
|
||||
) {
|
||||
FlagUtils.markUpdate(processing);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function canCapturePromise(vNode: VNode | null): boolean {
|
||||
return vNode?.suspenseChildStatus !== SuspenseChildStatus.ShowFallback && vNode?.props.fallback !== undefined;
|
||||
}
|
||||
|
||||
// 处理Suspense子组件抛出的promise
|
||||
export function handleSuspenseChildThrowError(parent: VNode, processing: VNode, error: any): boolean {
|
||||
export function handleSuspenseChildThrowError(parent: VNode | null, processing: VNode, error: any): boolean {
|
||||
let vNode = parent;
|
||||
|
||||
// 向上找到最近的不在fallback状态的Suspense,并触发重新渲染
|
||||
do {
|
||||
if (vNode.tag === SuspenseComponent && canCapturePromise(vNode)) {
|
||||
if (vNode?.tag === SuspenseComponent && canCapturePromise(vNode)) {
|
||||
if (vNode.suspensePromises === null) {
|
||||
vNode.suspensePromises = new Set();
|
||||
}
|
||||
|
@ -196,36 +200,8 @@ export function handleSuspenseChildThrowError(parent: VNode, processing: VNode,
|
|||
return false;
|
||||
}
|
||||
|
||||
function canCapturePromise(vNode: VNode): boolean {
|
||||
return vNode.suspenseChildStatus !== SuspenseChildStatus.ShowFallback && vNode.props.fallback !== undefined;
|
||||
}
|
||||
|
||||
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
|
||||
|
||||
// 对于每个promise,添加一个侦听器,以便当它resolve时,重新渲染
|
||||
export function listenToPromise(suspenseVNode: VNode) {
|
||||
const promises: Set<PromiseType<any>> | null = suspenseVNode.suspensePromises;
|
||||
if (promises !== null) {
|
||||
suspenseVNode.suspensePromises = null;
|
||||
|
||||
// 记录已经监听的 promise
|
||||
let promiseCache = suspenseVNode.realNode;
|
||||
if (promiseCache === null) {
|
||||
// @ts-ignore
|
||||
promiseCache = suspenseVNode.realNode = new PossiblyWeakSet();
|
||||
}
|
||||
|
||||
promises.forEach(promise => {
|
||||
const resole = resolvePromise.bind(null, suspenseVNode, promise);
|
||||
if (!promiseCache.has(promise)) {
|
||||
promiseCache.add(promise);
|
||||
// 监听promise
|
||||
promise.then(resole, resole);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) {
|
||||
const promiseCache = suspenseVNode.realNode;
|
||||
if (promiseCache !== null) {
|
||||
|
@ -238,4 +214,27 @@ function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) {
|
|||
}
|
||||
}
|
||||
|
||||
// 对于每个promise,添加一个侦听器,以便当它resolve时,重新渲染
|
||||
export function listenToPromise(suspenseVNode: VNode) {
|
||||
const promises: Set<PromiseType<any>> | null = suspenseVNode.suspensePromises;
|
||||
if (promises !== null) {
|
||||
suspenseVNode.suspensePromises = null;
|
||||
|
||||
// 记录已经监听的 promise
|
||||
let promiseCache = suspenseVNode.realNode;
|
||||
if (promiseCache === null) {
|
||||
// @ts-ignore
|
||||
promiseCache = new PossiblyWeakSet();
|
||||
suspenseVNode.realNode = new PossiblyWeakSet();
|
||||
}
|
||||
|
||||
promises.forEach(promise => {
|
||||
const resole = resolvePromise.bind(null, suspenseVNode, promise);
|
||||
if (!promiseCache.has(promise)) {
|
||||
promiseCache.add(promise);
|
||||
// 监听promise
|
||||
promise.then(resole, resole);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,10 +6,6 @@ import {resetNamespaceCtx, setNamespaceCtx} from '../ContextSaver';
|
|||
import {resetOldCtx} from '../components/context/CompatibleContext';
|
||||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return updateTreeRoot(processing);
|
||||
}
|
||||
|
||||
export function bubbleRender(processing: VNode) {
|
||||
resetNamespaceCtx(processing);
|
||||
resetOldCtx(processing);
|
||||
|
@ -40,3 +36,7 @@ function updateTreeRoot(processing) {
|
|||
processing.child = createVNodeChildren(processing, newElement);
|
||||
return processing.child;
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return updateTreeRoot(processing);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import type { VNode } from '../../Types';
|
||||
import type { Callback } from '../../UpdateHandler';
|
||||
|
||||
import {shallowCompare} from '../../utils/compare';
|
||||
import { shallowCompare } from '../../utils/compare';
|
||||
import {
|
||||
pushUpdate,
|
||||
newUpdate,
|
||||
|
@ -25,9 +25,11 @@ export function callDerivedStateFromProps(
|
|||
const newState = getDerivedStateFromProps(nextProps, oldState);
|
||||
|
||||
// 组件未返回state,需要返回旧的preState
|
||||
processing.state = newState === null || newState === undefined
|
||||
? oldState
|
||||
: { ...oldState, ...newState };
|
||||
if (newState) {
|
||||
processing.state = { ...oldState, ...newState };
|
||||
return;
|
||||
}
|
||||
processing.state = oldState;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -40,7 +42,7 @@ function changeStateContent(type: UpdateState, content: object, callback: Callba
|
|||
if (type === UpdateState.Update || type === UpdateState.Override) {
|
||||
update.content = content;
|
||||
}
|
||||
if (callback !== undefined && callback !== null) {
|
||||
if (callback) {
|
||||
update.callback = callback;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue