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 {TreeRoot} from '../renderer/vnode/VNodeTags';
|
||||||
import {Callback} from '../renderer/UpdateHandler';
|
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) {
|
function createRoot(children: any, container: Container, callback?: Callback) {
|
||||||
// 清空容器
|
// 清空容器
|
||||||
let child = container.lastChild;
|
let child = container.lastChild;
|
||||||
|
@ -66,8 +42,32 @@ function createRoot(children: any, container: Container, callback?: Callback) {
|
||||||
return treeRoot;
|
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 {
|
function findDOMNode(domOrEle: Element): null | Element | Text {
|
||||||
if (domOrEle == null) {
|
if (!domOrEle) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,7 +72,7 @@ export function getNearestVNode(dom: Node): null | VNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取 vNode 上的属性相关信息
|
// 获取 vNode 上的属性相关信息
|
||||||
export function getVNodeProps(dom: Element | Text): Props {
|
export function getVNodeProps(dom: Element | Text): Props | null{
|
||||||
return dom[internalKeys.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> {
|
export function getEventToListenerMap(target: EventTarget): Map<string, EventListener> {
|
||||||
let eventsMap = target[internalKeys.nonDelegatedEvents];
|
let eventsMap = target[internalKeys.nonDelegatedEvents];
|
||||||
if (!eventsMap) {
|
if (!eventsMap) {
|
||||||
eventsMap = target[internalKeys.nonDelegatedEvents] = new Map();
|
eventsMap = new Map();
|
||||||
|
target[internalKeys.nonDelegatedEvents] = new Map();
|
||||||
}
|
}
|
||||||
return eventsMap;
|
return eventsMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,13 +5,13 @@ import {
|
||||||
import {
|
import {
|
||||||
createDom,
|
createDom,
|
||||||
} from './utils/DomCreator';
|
} from './utils/DomCreator';
|
||||||
import {getSelectionInfo, resetSelectionRange, selectionData} from './SelectionRangeHandler';
|
import { getSelectionInfo, resetSelectionRange, selectionData } from './SelectionRangeHandler';
|
||||||
import {isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus} from './utils/Common';
|
import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
|
||||||
import {NSS} from './utils/DomCreator';
|
import { NSS } from './utils/DomCreator';
|
||||||
import {adjustStyleValue} from './DOMPropertiesHandler/StyleHandler';
|
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||||
|
|
||||||
import {listenDelegatedEvents} from '../event/EventBinding';
|
import { listenDelegatedEvents } from '../event/EventBinding';
|
||||||
import type {VNode} from '../renderer/Types';
|
import type { VNode } from '../renderer/Types';
|
||||||
import {
|
import {
|
||||||
setInitValue,
|
setInitValue,
|
||||||
getPropsWithoutValue,
|
getPropsWithoutValue,
|
||||||
|
@ -21,10 +21,10 @@ import {
|
||||||
compareProps,
|
compareProps,
|
||||||
setDomProps, updateDomProps
|
setDomProps, updateDomProps
|
||||||
} from './DOMPropertiesHandler/DOMPropertiesHandler';
|
} from './DOMPropertiesHandler/DOMPropertiesHandler';
|
||||||
import {isNativeElement, validateProps} from './validators/ValidateProps';
|
import { isNativeElement, validateProps } from './validators/ValidateProps';
|
||||||
import {watchValueChange} from './valueHandler/ValueChangeHandler';
|
import { watchValueChange } from './valueHandler/ValueChangeHandler';
|
||||||
import {DomComponent, DomText} from '../renderer/vnode/VNodeTags';
|
import { DomComponent, DomText } from '../renderer/vnode/VNodeTags';
|
||||||
import {updateCommonProp} from './DOMPropertiesHandler/UpdateCommonProp';
|
import { updateCommonProp } from './DOMPropertiesHandler/UpdateCommonProp';
|
||||||
|
|
||||||
export type Props = {
|
export type Props = {
|
||||||
autoFocus?: boolean;
|
autoFocus?: boolean;
|
||||||
|
@ -55,13 +55,7 @@ function getChildNS(parentNS: string | null, tagName: string): string {
|
||||||
|
|
||||||
// 获取容器
|
// 获取容器
|
||||||
export function getNSCtx(dom: Container, parentNS: string, type: string): string {
|
export function getNSCtx(dom: Container, parentNS: string, type: string): string {
|
||||||
let namespace;
|
return dom ? getChildNS(dom.namespaceURI ?? null, dom.nodeName) : getChildNS(parentNS, type);
|
||||||
if (dom) {
|
|
||||||
namespace = getChildNS(dom.namespaceURI ?? null, dom.nodeName);
|
|
||||||
} else {
|
|
||||||
namespace = getChildNS(parentNS, type);
|
|
||||||
}
|
|
||||||
return namespace;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function prepareForSubmit(): void {
|
export function prepareForSubmit(): void {
|
||||||
|
@ -156,7 +150,7 @@ export function newTextDom(
|
||||||
// 提交vNode的类型为Component或者Text的更新
|
// 提交vNode的类型为Component或者Text的更新
|
||||||
export function submitDomUpdate(tag: string, vNode: VNode) {
|
export function submitDomUpdate(tag: string, vNode: VNode) {
|
||||||
const newProps = vNode.props;
|
const newProps = vNode.props;
|
||||||
const element: Element = vNode.realNode;
|
const element: Element | null = vNode.realNode;
|
||||||
|
|
||||||
if (tag === DomComponent) {
|
if (tag === DomComponent) {
|
||||||
// DomComponent类型
|
// DomComponent类型
|
||||||
|
@ -179,8 +173,10 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (tag === DomText) {
|
} else if (tag === DomText) {
|
||||||
// text类型
|
if (element != null) {
|
||||||
element.textContent = newProps;
|
// text类型
|
||||||
|
element.textContent = newProps;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,27 @@ import {
|
||||||
} from '../../event/EventBinding';
|
} from '../../event/EventBinding';
|
||||||
import { isEventProp, isNativeElement } from '../validators/ValidateProps';
|
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属性
|
// 初始化DOM属性
|
||||||
export function setDomProps(
|
export function setDomProps(
|
||||||
tagName: string,
|
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 属性的差别,生成需要更新的属性集合
|
// 找出两个 DOM 属性的差别,生成需要更新的属性集合
|
||||||
export function compareProps(
|
export function compareProps(
|
||||||
oldProps: Object,
|
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(
|
processingListenerList = processingListenerList.concat(getCompositionListeners(
|
||||||
nativeEvtName,
|
nativeEvtName,
|
||||||
nativeEvent,
|
nativeEvent,
|
||||||
|
@ -183,13 +185,14 @@ export function handleEventMain(
|
||||||
|
|
||||||
// 有事件正在执行,同步执行事件
|
// 有事件正在执行,同步执行事件
|
||||||
if (isInEventsExecution) {
|
if (isInEventsExecution) {
|
||||||
return triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
|
triggerHorizonEvents(nativeEvtName, isCapture, nativeEvent, rootVNode);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 没有事件在执行,经过调度再执行事件
|
// 没有事件在执行,经过调度再执行事件
|
||||||
isInEventsExecution = true;
|
isInEventsExecution = true;
|
||||||
try {
|
try {
|
||||||
return asyncUpdates(() =>
|
asyncUpdates(() =>
|
||||||
triggerHorizonEvents(
|
triggerHorizonEvents(
|
||||||
nativeEvtName,
|
nativeEvtName,
|
||||||
isCapture,
|
isCapture,
|
||||||
|
|
|
@ -5,15 +5,6 @@ import {handleEventMain} from './HorizonEventMain';
|
||||||
import {runDiscreteUpdates} from '../renderer/Renderer';
|
import {runDiscreteUpdates} from '../renderer/Renderer';
|
||||||
import {getEventTarget} from './utils';
|
import {getEventTarget} from './utils';
|
||||||
|
|
||||||
// 生成委托事件的监听方法
|
|
||||||
export function createCustomEventListener(
|
|
||||||
target: EventTarget,
|
|
||||||
nativeEvtName: string,
|
|
||||||
isCapture: boolean,
|
|
||||||
): EventListener {
|
|
||||||
return triggerDelegatedEvent.bind(null, nativeEvtName, isCapture, target);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 触发委托事件
|
// 触发委托事件
|
||||||
function triggerDelegatedEvent(
|
function triggerDelegatedEvent(
|
||||||
nativeEvtName: string,
|
nativeEvtName: string,
|
||||||
|
@ -39,3 +30,12 @@ function triggerDelegatedEvent(
|
||||||
}
|
}
|
||||||
handleEventMain(nativeEvtName, isCapture, nativeEvent, targetVNode, targetDom);
|
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';
|
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 {
|
export class CustomBaseEvent {
|
||||||
|
|
||||||
data: string;
|
data: string;
|
||||||
|
@ -79,46 +121,3 @@ export class CustomBaseEvent {
|
||||||
this.isPropagationStopped = () => true;
|
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);
|
super(customEvtName, nativeEvtName, nativeEvt, vNode, target);
|
||||||
this.key = getKey(nativeEvt);
|
this.key = getKey(nativeEvt);
|
||||||
this.charCode = nativeEvtName === 'keypress' ? uniqueCharCode(nativeEvt) : 0;
|
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;
|
this.which = this.charCode || this.keyCode;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,7 @@ const SPACE_CHAR = String.fromCharCode(CHAR_CODE_SPACE);
|
||||||
function getInputCharsByNative(
|
function getInputCharsByNative(
|
||||||
eventName: string,
|
eventName: string,
|
||||||
nativeEvent: any,
|
nativeEvent: any,
|
||||||
): string | void {
|
): string | null | void {
|
||||||
if (eventName === 'compositionend') {
|
if (eventName === 'compositionend') {
|
||||||
return (nativeEvent.detail && nativeEvent.detail.data) || null;
|
return (nativeEvent.detail && nativeEvent.detail.data) || null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ const horizonEventName = 'onSelect'
|
||||||
|
|
||||||
let currentElement = null;
|
let currentElement = null;
|
||||||
let currentVNode = null;
|
let currentVNode = null;
|
||||||
let lastSelection = null;
|
let lastSelection: Selection | null = null;
|
||||||
|
|
||||||
function initTargetCache(dom, vNode) {
|
function initTargetCache(dom, vNode) {
|
||||||
if (isTextInputElement(dom) || dom.contentEditable === 'true') {
|
if (isTextInputElement(dom) || dom.contentEditable === 'true') {
|
||||||
|
@ -85,7 +85,7 @@ export function getListeners(
|
||||||
target: null | EventTarget,
|
target: null | EventTarget,
|
||||||
): ProcessingListenerList {
|
): ProcessingListenerList {
|
||||||
const targetNode = vNode ? getDom(vNode) : window;
|
const targetNode = vNode ? getDom(vNode) : window;
|
||||||
let eventUnitList = [];
|
let eventUnitList: ProcessingListenerList = [];
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'focusin':
|
case 'focusin':
|
||||||
initTargetCache(targetNode, vNode);
|
initTargetCache(targetNode, vNode);
|
||||||
|
|
|
@ -10,7 +10,18 @@ import {
|
||||||
cacheOldCtx,
|
cacheOldCtx,
|
||||||
} from '../components/context/CompatibleContext';
|
} 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 Component = processing.type;
|
||||||
const unresolvedProps = processing.props;
|
const unresolvedProps = processing.props;
|
||||||
const resolvedProps =
|
const resolvedProps =
|
||||||
|
@ -28,14 +39,3 @@ export function bubbleRender(processing: VNode) {
|
||||||
resetOldCtx(processing);
|
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 { captureClassComponent } from './ClassComponent';
|
||||||
import { captureMemoComponent } from './MemoComponent';
|
import { captureMemoComponent } from './MemoComponent';
|
||||||
|
|
||||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
|
||||||
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender() { }
|
export function bubbleRender() { }
|
||||||
|
|
||||||
const LazyRendererMap = {
|
const LazyRendererMap = {
|
||||||
|
@ -26,6 +22,20 @@ const LazyRendererMap = {
|
||||||
[MemoComponent]: captureMemoComponent,
|
[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(
|
function captureLazyComponent(
|
||||||
processing,
|
processing,
|
||||||
lazyComponent,
|
lazyComponent,
|
||||||
|
@ -43,7 +53,8 @@ function captureLazyComponent(
|
||||||
// 加载得到的Component存在type中
|
// 加载得到的Component存在type中
|
||||||
processing.type = Component;
|
processing.type = Component;
|
||||||
|
|
||||||
const lazyVNodeTag = processing.tag = getLazyVNodeTag(Component);
|
const lazyVNodeTag = getLazyVNodeTag(Component);
|
||||||
|
processing.tag = getLazyVNodeTag(Component);
|
||||||
const lazyVNodeProps = mergeDefaultProps(Component, processing.props);
|
const lazyVNodeProps = mergeDefaultProps(Component, processing.props);
|
||||||
|
|
||||||
const lazyRender = LazyRendererMap[lazyVNodeTag];
|
const lazyRender = LazyRendererMap[lazyVNodeTag];
|
||||||
|
@ -68,16 +79,6 @@ function captureLazyComponent(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function mergeDefaultProps(Component: any, props: object): object {
|
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||||
if (Component && Component.defaultProps) {
|
return captureLazyComponent(processing, processing.type, shouldUpdate);
|
||||||
const clonedProps = { ...props };
|
|
||||||
const defaultProps = Component.defaultProps;
|
|
||||||
Object.keys(defaultProps).forEach(key => {
|
|
||||||
if (clonedProps[key] === undefined) {
|
|
||||||
clonedProps[key] = defaultProps[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return clonedProps;
|
|
||||||
}
|
|
||||||
return props;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,107 +19,6 @@ export enum SuspenseChildStatus {
|
||||||
ShowFallback = 'showFallback',
|
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子节点
|
// 创建fallback子节点
|
||||||
function createFallback(processing: VNode, fallbackChildren) {
|
function createFallback(processing: VNode, fallbackChildren) {
|
||||||
const childFragment: VNode = processing.child;
|
const childFragment: VNode = processing.child;
|
||||||
|
@ -152,13 +51,118 @@ function createFallback(processing: VNode, fallbackChildren) {
|
||||||
return fallbackFragment;
|
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
|
// 处理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;
|
let vNode = parent;
|
||||||
|
|
||||||
// 向上找到最近的不在fallback状态的Suspense,并触发重新渲染
|
// 向上找到最近的不在fallback状态的Suspense,并触发重新渲染
|
||||||
do {
|
do {
|
||||||
if (vNode.tag === SuspenseComponent && canCapturePromise(vNode)) {
|
if (vNode?.tag === SuspenseComponent && canCapturePromise(vNode)) {
|
||||||
if (vNode.suspensePromises === null) {
|
if (vNode.suspensePromises === null) {
|
||||||
vNode.suspensePromises = new Set();
|
vNode.suspensePromises = new Set();
|
||||||
}
|
}
|
||||||
|
@ -196,36 +200,8 @@ export function handleSuspenseChildThrowError(parent: VNode, processing: VNode,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function canCapturePromise(vNode: VNode): boolean {
|
|
||||||
return vNode.suspenseChildStatus !== SuspenseChildStatus.ShowFallback && vNode.props.fallback !== undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const PossiblyWeakSet = typeof WeakSet === 'function' ? WeakSet : Set;
|
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>) {
|
function resolvePromise(suspenseVNode: VNode, promise: PromiseType<any>) {
|
||||||
const promiseCache = suspenseVNode.realNode;
|
const promiseCache = suspenseVNode.realNode;
|
||||||
if (promiseCache !== null) {
|
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 {resetOldCtx} from '../components/context/CompatibleContext';
|
||||||
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
import {onlyUpdateChildVNodes} from '../vnode/VNodeCreator';
|
||||||
|
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
|
||||||
return updateTreeRoot(processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
resetNamespaceCtx(processing);
|
resetNamespaceCtx(processing);
|
||||||
resetOldCtx(processing);
|
resetOldCtx(processing);
|
||||||
|
@ -40,3 +36,7 @@ function updateTreeRoot(processing) {
|
||||||
processing.child = createVNodeChildren(processing, newElement);
|
processing.child = createVNodeChildren(processing, newElement);
|
||||||
return processing.child;
|
return processing.child;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function captureRender(processing: VNode): VNode | null {
|
||||||
|
return updateTreeRoot(processing);
|
||||||
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import type { VNode } from '../../Types';
|
import type { VNode } from '../../Types';
|
||||||
import type { Callback } from '../../UpdateHandler';
|
import type { Callback } from '../../UpdateHandler';
|
||||||
|
|
||||||
import {shallowCompare} from '../../utils/compare';
|
import { shallowCompare } from '../../utils/compare';
|
||||||
import {
|
import {
|
||||||
pushUpdate,
|
pushUpdate,
|
||||||
newUpdate,
|
newUpdate,
|
||||||
|
@ -25,9 +25,11 @@ export function callDerivedStateFromProps(
|
||||||
const newState = getDerivedStateFromProps(nextProps, oldState);
|
const newState = getDerivedStateFromProps(nextProps, oldState);
|
||||||
|
|
||||||
// 组件未返回state,需要返回旧的preState
|
// 组件未返回state,需要返回旧的preState
|
||||||
processing.state = newState === null || newState === undefined
|
if (newState) {
|
||||||
? oldState
|
processing.state = { ...oldState, ...newState };
|
||||||
: { ...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) {
|
if (type === UpdateState.Update || type === UpdateState.Override) {
|
||||||
update.content = content;
|
update.content = content;
|
||||||
}
|
}
|
||||||
if (callback !== undefined && callback !== null) {
|
if (callback) {
|
||||||
update.callback = callback;
|
update.callback = callback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue