Match-id-cc46c9f90ee2c1f0d758534ce54c0583577b42ce
This commit is contained in:
commit
b0f4ffa7bf
|
@ -120,7 +120,7 @@ const Horizon = {
|
||||||
isMemo,
|
isMemo,
|
||||||
isPortal,
|
isPortal,
|
||||||
isContextProvider,
|
isContextProvider,
|
||||||
isContextConsumer
|
isContextConsumer,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const version = __VERSION__;
|
export const version = __VERSION__;
|
||||||
|
@ -171,7 +171,7 @@ export {
|
||||||
isMemo,
|
isMemo,
|
||||||
isPortal,
|
isPortal,
|
||||||
isContextProvider,
|
isContextProvider,
|
||||||
isContextConsumer
|
isContextConsumer,
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Horizon;
|
export default Horizon;
|
||||||
|
|
|
@ -18,16 +18,9 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { VNode } from '../renderer/Types';
|
import type { VNode } from '../renderer/Types';
|
||||||
import type {
|
import type { Container, Props } from './DOMOperator';
|
||||||
Container,
|
|
||||||
Props,
|
|
||||||
} from './DOMOperator';
|
|
||||||
|
|
||||||
import {
|
import { DomComponent, DomText, TreeRoot } from '../renderer/vnode/VNodeTags';
|
||||||
DomComponent,
|
|
||||||
DomText,
|
|
||||||
TreeRoot,
|
|
||||||
} from '../renderer/vnode/VNodeTags';
|
|
||||||
|
|
||||||
const INTERNAL_VNODE = '_horizon_VNode';
|
const INTERNAL_VNODE = '_horizon_VNode';
|
||||||
const INTERNAL_PROPS = '_horizon_Props';
|
const INTERNAL_PROPS = '_horizon_Props';
|
||||||
|
@ -43,10 +36,7 @@ export function getDom(vNode: VNode): Element | Text | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 VNode 属性相关信息挂到 DOM 对象的特定属性上
|
// 将 VNode 属性相关信息挂到 DOM 对象的特定属性上
|
||||||
export function saveVNode(
|
export function saveVNode(vNode: VNode, dom: Element | Text | Container): void {
|
||||||
vNode: VNode,
|
|
||||||
dom: Element | Text | Container,
|
|
||||||
): void {
|
|
||||||
dom[INTERNAL_VNODE] = vNode;
|
dom[INTERNAL_VNODE] = vNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,27 +13,15 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { saveVNode, updateVNodeProps } from './DOMInternalKeys';
|
||||||
saveVNode,
|
import { createDom } from './utils/DomCreator';
|
||||||
updateVNodeProps,
|
|
||||||
} from './DOMInternalKeys';
|
|
||||||
import {
|
|
||||||
createDom,
|
|
||||||
} from './utils/DomCreator';
|
|
||||||
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
||||||
import { shouldAutoFocus } from './utils/Common';
|
import { 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 type { VNode } from '../renderer/Types';
|
import type { VNode } from '../renderer/Types';
|
||||||
import {
|
import { setInitValue, getPropsWithoutValue, updateValue } from './valueHandler';
|
||||||
setInitValue,
|
import { compareProps, setDomProps } from './DOMPropertiesHandler/DOMPropertiesHandler';
|
||||||
getPropsWithoutValue,
|
|
||||||
updateValue,
|
|
||||||
} from './valueHandler';
|
|
||||||
import {
|
|
||||||
compareProps,
|
|
||||||
setDomProps,
|
|
||||||
} 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';
|
||||||
|
@ -81,12 +69,7 @@ export function resetAfterSubmit(): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建 DOM 对象
|
// 创建 DOM 对象
|
||||||
export function newDom(
|
export function newDom(tagName: string, props: Props, parentNamespace: string, vNode: VNode): Element {
|
||||||
tagName: string,
|
|
||||||
props: Props,
|
|
||||||
parentNamespace: string,
|
|
||||||
vNode: VNode,
|
|
||||||
): Element {
|
|
||||||
const dom: Element = createDom(tagName, parentNamespace);
|
const dom: Element = createDom(tagName, parentNamespace);
|
||||||
// 将 vNode 节点挂到 DOM 对象上
|
// 将 vNode 节点挂到 DOM 对象上
|
||||||
saveVNode(vNode, dom);
|
saveVNode(vNode, dom);
|
||||||
|
@ -119,12 +102,7 @@ export function initDomProps(dom: Element, tagName: string, rawProps: Props): bo
|
||||||
}
|
}
|
||||||
|
|
||||||
// 准备更新之前进行一系列校验 DOM,寻找属性差异等准备工作
|
// 准备更新之前进行一系列校验 DOM,寻找属性差异等准备工作
|
||||||
export function getPropChangeList(
|
export function getPropChangeList(dom: Element, type: string, lastRawProps: Props, nextRawProps: Props): Object {
|
||||||
dom: Element,
|
|
||||||
type: string,
|
|
||||||
lastRawProps: Props,
|
|
||||||
nextRawProps: Props,
|
|
||||||
): Object {
|
|
||||||
// 校验两个对象的不同
|
// 校验两个对象的不同
|
||||||
validateProps(type, nextRawProps);
|
validateProps(type, nextRawProps);
|
||||||
|
|
||||||
|
@ -151,10 +129,7 @@ export function isTextChild(type: string, props: Props): boolean {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function newTextDom(
|
export function newTextDom(text: string, processing: VNode): Text {
|
||||||
text: string,
|
|
||||||
processing: VNode,
|
|
||||||
): Text {
|
|
||||||
const textNode: Text = document.createTextNode(text);
|
const textNode: Text = document.createTextNode(text);
|
||||||
saveVNode(processing, textNode);
|
saveVNode(processing, textNode);
|
||||||
return textNode;
|
return textNode;
|
||||||
|
@ -198,26 +173,16 @@ export function clearText(dom: Element): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加child元素
|
// 添加child元素
|
||||||
export function appendChildElement(
|
export function appendChildElement(parent: Element | Container, child: Element | Text): void {
|
||||||
parent: Element | Container,
|
|
||||||
child: Element | Text
|
|
||||||
): void {
|
|
||||||
parent.appendChild(child);
|
parent.appendChild(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 插入dom元素
|
// 插入dom元素
|
||||||
export function insertDomBefore(
|
export function insertDomBefore(parent: Element | Container, child: Element | Text, beforeChild: Element | Text) {
|
||||||
parent: Element | Container,
|
|
||||||
child: Element | Text,
|
|
||||||
beforeChild: Element | Text,
|
|
||||||
) {
|
|
||||||
parent.insertBefore(child, beforeChild);
|
parent.insertBefore(child, beforeChild);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function removeChildDom(
|
export function removeChildDom(parent: Element | Container, child: Element | Text) {
|
||||||
parent: Element | Container,
|
|
||||||
child: Element | Text
|
|
||||||
) {
|
|
||||||
parent.removeChild(child);
|
parent.removeChild(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,11 +81,7 @@ export function compareProps(oldProps: Object, newProps: Object): Object {
|
||||||
styleProp = styleProps[j];
|
styleProp = styleProps[j];
|
||||||
updatesForStyle[styleProp] = '';
|
updatesForStyle[styleProp] = '';
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (propName === 'autoFocus' || propName === 'children' || propName === 'dangerouslySetInnerHTML') {
|
||||||
propName === 'autoFocus' ||
|
|
||||||
propName === 'children' ||
|
|
||||||
propName === 'dangerouslySetInnerHTML'
|
|
||||||
) {
|
|
||||||
continue;
|
continue;
|
||||||
} else if (isEventProp(propName)) {
|
} else if (isEventProp(propName)) {
|
||||||
if (!allDelegatedHorizonEvents.has(propName)) {
|
if (!allDelegatedHorizonEvents.has(propName)) {
|
||||||
|
|
|
@ -14,14 +14,16 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
function isNeedUnitCSS(styleName: string) {
|
function isNeedUnitCSS(styleName: string) {
|
||||||
return !(noUnitCSS.includes(styleName)
|
return !(
|
||||||
|| styleName.startsWith('borderImage')
|
noUnitCSS.includes(styleName) ||
|
||||||
|| styleName.startsWith('flex')
|
styleName.startsWith('borderImage') ||
|
||||||
|| styleName.startsWith('gridRow')
|
styleName.startsWith('flex') ||
|
||||||
|| styleName.startsWith('gridColumn')
|
styleName.startsWith('gridRow') ||
|
||||||
|| styleName.startsWith('stroke')
|
styleName.startsWith('gridColumn') ||
|
||||||
|| styleName.startsWith('box')
|
styleName.startsWith('stroke') ||
|
||||||
|| styleName.endsWith('Opacity'));
|
styleName.startsWith('box') ||
|
||||||
|
styleName.endsWith('Opacity')
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,7 +52,7 @@ export function setStyles(dom, styles) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const style = dom.style;
|
const style = dom.style;
|
||||||
Object.keys(styles).forEach((name) => {
|
Object.keys(styles).forEach(name => {
|
||||||
const styleVal = styles[name];
|
const styleVal = styles[name];
|
||||||
|
|
||||||
style[name] = adjustStyleValue(name, styleVal);
|
style[name] = adjustStyleValue(name, styleVal);
|
||||||
|
@ -60,5 +62,19 @@ export function setStyles(dom, styles) {
|
||||||
/**
|
/**
|
||||||
* 不需要加长度单位的 css 属性
|
* 不需要加长度单位的 css 属性
|
||||||
*/
|
*/
|
||||||
const noUnitCSS = ['animationIterationCount', 'columnCount', 'columns', 'gridArea', 'fontWeight', 'lineClamp',
|
const noUnitCSS = [
|
||||||
'lineHeight', 'opacity', 'order', 'orphans', 'tabSize', 'widows', 'zIndex', 'zoom'];
|
'animationIterationCount',
|
||||||
|
'columnCount',
|
||||||
|
'columns',
|
||||||
|
'gridArea',
|
||||||
|
'fontWeight',
|
||||||
|
'lineClamp',
|
||||||
|
'lineHeight',
|
||||||
|
'opacity',
|
||||||
|
'order',
|
||||||
|
'orphans',
|
||||||
|
'tabSize',
|
||||||
|
'widows',
|
||||||
|
'zIndex',
|
||||||
|
'zoom',
|
||||||
|
];
|
||||||
|
|
|
@ -13,25 +13,77 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { getPropDetails, PROPERTY_TYPE } from '../validators/PropertiesData';
|
||||||
getPropDetails,
|
|
||||||
PROPERTY_TYPE,
|
|
||||||
} from '../validators/PropertiesData';
|
|
||||||
import { isInvalidValue } from '../validators/ValidateProps';
|
import { isInvalidValue } from '../validators/ValidateProps';
|
||||||
import { getNamespaceCtx } from '../../renderer/ContextSaver';
|
import { getNamespaceCtx } from '../../renderer/ContextSaver';
|
||||||
import { NSS } from '../utils/DomCreator';
|
import { NSS } from '../utils/DomCreator';
|
||||||
import { getDomTag } from '../utils/Common';
|
import { getDomTag } from '../utils/Common';
|
||||||
|
|
||||||
const svgHumpAttr = new Set(['allowReorder', 'autoReverse', 'baseFrequency', 'baseProfile', 'calcMode', 'clipPathUnits',
|
const svgHumpAttr = new Set([
|
||||||
'contentScriptType', 'contentStyleType', 'diffuseConstant', 'edgeMode', 'externalResourcesRequired', 'filterRes',
|
'allowReorder',
|
||||||
'filterUnits', 'glyphRef', 'gradientTransform', 'gradientUnits', 'kernelMatrix', 'kernelUnitLength', 'keyPoints',
|
'autoReverse',
|
||||||
'keySplines', 'keyTimes', 'lengthAdjust', 'limitingConeAngle', 'markerHeight', 'markerUnits', 'markerWidth',
|
'baseFrequency',
|
||||||
'maskContentUnits', 'maskUnits', 'numOctaves', 'pathLength', 'patternContentUnits', 'patternTransform,',
|
'baseProfile',
|
||||||
'patternUnits', 'pointsAtX', 'pointsAtY', 'pointsAtZ', 'preserveAlpha', 'preserveAspectRatio', 'primitiveUnits',
|
'calcMode',
|
||||||
'referrerPolicy', 'refX', 'refY', 'repeatCount', 'repeatDur', 'requiredExtensions', 'requiredFeatures',
|
'clipPathUnits',
|
||||||
'specularConstant', 'specularExponent', 'spreadMethod', 'startOffset', 'stdDeviation',
|
'contentScriptType',
|
||||||
'stitchTiles', 'surfaceScale','systemLanguage', 'tableValues', 'targetX', 'targetY',
|
'contentStyleType',
|
||||||
'textLength','viewBox', 'viewTarget', 'xChannelSelector','yChannelSelector', 'zoomAndPan']);
|
'diffuseConstant',
|
||||||
|
'edgeMode',
|
||||||
|
'externalResourcesRequired',
|
||||||
|
'filterRes',
|
||||||
|
'filterUnits',
|
||||||
|
'glyphRef',
|
||||||
|
'gradientTransform',
|
||||||
|
'gradientUnits',
|
||||||
|
'kernelMatrix',
|
||||||
|
'kernelUnitLength',
|
||||||
|
'keyPoints',
|
||||||
|
'keySplines',
|
||||||
|
'keyTimes',
|
||||||
|
'lengthAdjust',
|
||||||
|
'limitingConeAngle',
|
||||||
|
'markerHeight',
|
||||||
|
'markerUnits',
|
||||||
|
'markerWidth',
|
||||||
|
'maskContentUnits',
|
||||||
|
'maskUnits',
|
||||||
|
'numOctaves',
|
||||||
|
'pathLength',
|
||||||
|
'patternContentUnits',
|
||||||
|
'patternTransform,',
|
||||||
|
'patternUnits',
|
||||||
|
'pointsAtX',
|
||||||
|
'pointsAtY',
|
||||||
|
'pointsAtZ',
|
||||||
|
'preserveAlpha',
|
||||||
|
'preserveAspectRatio',
|
||||||
|
'primitiveUnits',
|
||||||
|
'referrerPolicy',
|
||||||
|
'refX',
|
||||||
|
'refY',
|
||||||
|
'repeatCount',
|
||||||
|
'repeatDur',
|
||||||
|
'requiredExtensions',
|
||||||
|
'requiredFeatures',
|
||||||
|
'specularConstant',
|
||||||
|
'specularExponent',
|
||||||
|
'spreadMethod',
|
||||||
|
'startOffset',
|
||||||
|
'stdDeviation',
|
||||||
|
'stitchTiles',
|
||||||
|
'surfaceScale',
|
||||||
|
'systemLanguage',
|
||||||
|
'tableValues',
|
||||||
|
'targetX',
|
||||||
|
'targetY',
|
||||||
|
'textLength',
|
||||||
|
'viewBox',
|
||||||
|
'viewTarget',
|
||||||
|
'xChannelSelector',
|
||||||
|
'yChannelSelector',
|
||||||
|
'zoomAndPan',
|
||||||
|
]);
|
||||||
|
|
||||||
// 驼峰 变 “-”
|
// 驼峰 变 “-”
|
||||||
function convertToLowerCase(str) {
|
function convertToLowerCase(str) {
|
||||||
|
@ -65,19 +117,22 @@ export function updateCommonProp(dom: Element, attrName: string, value: any, isN
|
||||||
dom.setAttribute(attrName, String(value));
|
dom.setAttribute(attrName, String(value));
|
||||||
}
|
}
|
||||||
} else if (['checked', 'multiple', 'muted', 'selected'].includes(propDetails.attrName)) {
|
} else if (['checked', 'multiple', 'muted', 'selected'].includes(propDetails.attrName)) {
|
||||||
if (value === null) { // 必填属性设置默认值
|
if (value === null) {
|
||||||
|
// 必填属性设置默认值
|
||||||
dom[propDetails.attrName] = false;
|
dom[propDetails.attrName] = false;
|
||||||
} else {
|
} else {
|
||||||
dom[propDetails.attrName] = value;
|
dom[propDetails.attrName] = value;
|
||||||
}
|
}
|
||||||
} else { // 处理其他普通属性
|
} else {
|
||||||
|
// 处理其他普通属性
|
||||||
if (value === null) {
|
if (value === null) {
|
||||||
dom.removeAttribute(propDetails.attrName);
|
dom.removeAttribute(propDetails.attrName);
|
||||||
} else {
|
} else {
|
||||||
const { type, attrNS } = propDetails; // 数据类型、固有属性命名空间
|
const { type, attrNS } = propDetails; // 数据类型、固有属性命名空间
|
||||||
const attributeName = propDetails.attrName; // 固有属性名
|
const attributeName = propDetails.attrName; // 固有属性名
|
||||||
let attributeValue;
|
let attributeValue;
|
||||||
if (type === PROPERTY_TYPE.BOOLEAN) { // 即可以用作标志又可以是属性值的属性
|
if (type === PROPERTY_TYPE.BOOLEAN) {
|
||||||
|
// 即可以用作标志又可以是属性值的属性
|
||||||
attributeValue = '';
|
attributeValue = '';
|
||||||
} else {
|
} else {
|
||||||
attributeValue = String(value);
|
attributeValue = String(value);
|
||||||
|
|
|
@ -76,7 +76,8 @@ function isNodeContainsByTargetNode(targetNode, node) {
|
||||||
if (typeof targetNode.contains === 'function') {
|
if (typeof targetNode.contains === 'function') {
|
||||||
return targetNode.contains(node); // 该的节点是否为目标节点的后代节点
|
return targetNode.contains(node); // 该的节点是否为目标节点的后代节点
|
||||||
}
|
}
|
||||||
if (typeof targetNode.compareDocumentPosition === 'function') { // compareDocumentPosition 数值,表示两个节点彼此做比较的位置
|
if (typeof targetNode.compareDocumentPosition === 'function') {
|
||||||
|
// compareDocumentPosition 数值,表示两个节点彼此做比较的位置
|
||||||
const CONTAINS_CODE = 16;
|
const CONTAINS_CODE = 16;
|
||||||
// 返回 16 代表 第二节点在第一节点内部
|
// 返回 16 代表 第二节点在第一节点内部
|
||||||
return targetNode.compareDocumentPosition(node) === CONTAINS_CODE;
|
return targetNode.compareDocumentPosition(node) === CONTAINS_CODE;
|
||||||
|
@ -153,7 +154,8 @@ export function resetSelectionRange(preSelectionRangeData: SelectionData) {
|
||||||
let ancestor = preFocusedDom.parentNode;
|
let ancestor = preFocusedDom.parentNode;
|
||||||
// 查找先前的 focus 节点的先祖
|
// 查找先前的 focus 节点的先祖
|
||||||
while (ancestor) {
|
while (ancestor) {
|
||||||
if (isElement(ancestor)) { // 是元素节点,就把先祖信息放到先祖数组中
|
if (isElement(ancestor)) {
|
||||||
|
// 是元素节点,就把先祖信息放到先祖数组中
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
const { scrollLeft, scrollTop } = ancestor;
|
const { scrollLeft, scrollTop } = ancestor;
|
||||||
ancestors.push({
|
ancestors.push({
|
||||||
|
|
|
@ -35,12 +35,15 @@ export function getIFrameFocusedDom() {
|
||||||
while (focusedDom instanceof currentWindow.HTMLIFrameElement) {
|
while (focusedDom instanceof currentWindow.HTMLIFrameElement) {
|
||||||
try {
|
try {
|
||||||
// 访问 HTMLIframeElement 的 contentDocument 可能会导致浏览器抛出错误
|
// 访问 HTMLIframeElement 的 contentDocument 可能会导致浏览器抛出错误
|
||||||
if (typeof focusedDom.contentWindow.location.href === 'string') { // iframe 的内容为同源
|
if (typeof focusedDom.contentWindow.location.href === 'string') {
|
||||||
|
// iframe 的内容为同源
|
||||||
focusedDom = getFocusedDom(focusedDom.contentWindow.document);
|
focusedDom = getFocusedDom(focusedDom.contentWindow.document);
|
||||||
} else { // 非同源 iframe 因为安全性原因无法获取其中的具体元素
|
} else {
|
||||||
|
// 非同源 iframe 因为安全性原因无法获取其中的具体元素
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} catch (e) { // 非同源 iframe 因为安全性原因无法获取其中的具体元素
|
} catch (e) {
|
||||||
|
// 非同源 iframe 因为安全性原因无法获取其中的具体元素
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||||
*
|
*
|
||||||
|
@ -21,10 +20,7 @@ export const NSS = {
|
||||||
};
|
};
|
||||||
|
|
||||||
// 创建DOM元素
|
// 创建DOM元素
|
||||||
export function createDom(
|
export function createDom(tagName: string, parentNamespace: string): Element {
|
||||||
tagName: string,
|
|
||||||
parentNamespace: string,
|
|
||||||
): Element {
|
|
||||||
let dom: Element;
|
let dom: Element;
|
||||||
const selfNamespace = NSS[tagName] || NSS.html;
|
const selfNamespace = NSS[tagName] || NSS.html;
|
||||||
const ns = parentNamespace !== NSS.html ? parentNamespace : selfNamespace;
|
const ns = parentNamespace !== NSS.html ? parentNamespace : selfNamespace;
|
||||||
|
|
|
@ -13,23 +13,16 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { getPropDetails, PROPERTY_TYPE, PropDetails } from './PropertiesData';
|
||||||
getPropDetails, PROPERTY_TYPE, PropDetails,
|
|
||||||
} from './PropertiesData';
|
|
||||||
|
|
||||||
const INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;
|
const INVALID_EVENT_NAME_REGEX = /^on[^A-Z]/;
|
||||||
|
|
||||||
|
|
||||||
// 是内置元素
|
// 是内置元素
|
||||||
export function isNativeElement(tagName: string, props: Record<string, any>) {
|
export function isNativeElement(tagName: string, props: Record<string, any>) {
|
||||||
return !tagName.includes('-') && props.is === undefined;
|
return !tagName.includes('-') && props.is === undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function isInvalidBoolean(
|
function isInvalidBoolean(attributeName: string, value: any, propDetails: PropDetails): boolean {
|
||||||
attributeName: string,
|
|
||||||
value: any,
|
|
||||||
propDetails: PropDetails,
|
|
||||||
): boolean {
|
|
||||||
if (propDetails.type === PROPERTY_TYPE.SPECIAL) {
|
if (propDetails.type === PROPERTY_TYPE.SPECIAL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -78,7 +71,7 @@ export function isInvalidValue(
|
||||||
name: string,
|
name: string,
|
||||||
value: any,
|
value: any,
|
||||||
propDetails: PropDetails | null,
|
propDetails: PropDetails | null,
|
||||||
isNativeTag: boolean,
|
isNativeTag: boolean
|
||||||
): boolean {
|
): boolean {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -122,11 +115,7 @@ export function validateProps(type, props) {
|
||||||
const propString = invalidProps.map(prop => '`' + prop + '`').join(', ');
|
const propString = invalidProps.map(prop => '`' + prop + '`').join(', ');
|
||||||
|
|
||||||
if (invalidProps.length >= 1) {
|
if (invalidProps.length >= 1) {
|
||||||
console.error(
|
console.error('Invalid value for prop %s on <%s> tag.', propString, type);
|
||||||
'Invalid value for prop %s on <%s> tag.',
|
|
||||||
propString,
|
|
||||||
type,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,7 +45,8 @@ export function getInputPropsWithoutValue(dom: HTMLInputElement, props: Props) {
|
||||||
export function updateInputValue(dom: HTMLInputElement, props: Props) {
|
export function updateInputValue(dom: HTMLInputElement, props: Props) {
|
||||||
const { value, checked } = props;
|
const { value, checked } = props;
|
||||||
|
|
||||||
if (value != null) { // 处理 dom.value 逻辑
|
if (value != null) {
|
||||||
|
// 处理 dom.value 逻辑
|
||||||
if (dom.value !== String(value)) {
|
if (dom.value !== String(value)) {
|
||||||
dom.value = String(value);
|
dom.value = String(value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import {HorizonSelect, Props} from '../utils/Interface';
|
||||||
function updateMultipleValue(options, newValues) {
|
function updateMultipleValue(options, newValues) {
|
||||||
const newValueSet = new Set();
|
const newValueSet = new Set();
|
||||||
|
|
||||||
newValues.forEach((val) => {
|
newValues.forEach(val => {
|
||||||
newValueSet.add(String(val));
|
newValueSet.add(String(val));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ export function getSelectPropsWithoutValue(dom: HorizonSelect, properties: Objec
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateSelectValue(dom: HorizonSelect, props: Props, isInit: boolean = false) {
|
export function updateSelectValue(dom: HorizonSelect, props: Props, isInit = false) {
|
||||||
const { value, defaultValue, multiple } = props;
|
const { value, defaultValue, multiple } = props;
|
||||||
|
|
||||||
const oldMultiple = dom._multiple !== undefined ? dom._multiple : dom.multiple;
|
const oldMultiple = dom._multiple !== undefined ? dom._multiple : dom.multiple;
|
||||||
|
@ -71,7 +71,8 @@ export function updateSelectValue(dom: HorizonSelect, props: Props, isInit: bool
|
||||||
// 设置了 value 属性
|
// 设置了 value 属性
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
updateValue(dom.options, value, newMultiple);
|
updateValue(dom.options, value, newMultiple);
|
||||||
} else if (oldMultiple !== newMultiple) { // 修改了 multiple 属性
|
} else if (oldMultiple !== newMultiple) {
|
||||||
|
// 修改了 multiple 属性
|
||||||
// 切换 multiple 之后,如果设置了 defaultValue 需要重新应用
|
// 切换 multiple 之后,如果设置了 defaultValue 需要重新应用
|
||||||
if (defaultValue != null) {
|
if (defaultValue != null) {
|
||||||
updateValue(dom.options, defaultValue, newMultiple);
|
updateValue(dom.options, defaultValue, newMultiple);
|
||||||
|
@ -79,7 +80,8 @@ export function updateSelectValue(dom: HorizonSelect, props: Props, isInit: bool
|
||||||
// 恢复到未选定状态
|
// 恢复到未选定状态
|
||||||
updateValue(dom.options, newMultiple ? [] : '', newMultiple);
|
updateValue(dom.options, newMultiple ? [] : '', newMultiple);
|
||||||
}
|
}
|
||||||
} else if (isInit && defaultValue != null) { // 设置了 defaultValue 属性
|
} else if (isInit && defaultValue != null) {
|
||||||
|
// 设置了 defaultValue 属性
|
||||||
updateValue(dom.options, defaultValue, newMultiple);
|
updateValue(dom.options, defaultValue, newMultiple);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
import { Props } from '../utils/Interface';
|
import { Props } from '../utils/Interface';
|
||||||
|
|
||||||
|
|
||||||
// 值的优先级 value > children > defaultValue
|
// 值的优先级 value > children > defaultValue
|
||||||
function getInitValue(props: Props) {
|
function getInitValue(props: Props) {
|
||||||
const { value } = props;
|
const { value } = props;
|
||||||
|
@ -45,7 +44,7 @@ export function getTextareaPropsWithoutValue(dom: HTMLTextAreaElement, propertie
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateTextareaValue(dom: HTMLTextAreaElement, props: Props, isInit: boolean = false) {
|
export function updateTextareaValue(dom: HTMLTextAreaElement, props: Props, isInit = false) {
|
||||||
if (isInit) {
|
if (isInit) {
|
||||||
const initValue = getInitValue(props);
|
const initValue = getInitValue(props);
|
||||||
if (initValue !== '') {
|
if (initValue !== '') {
|
||||||
|
@ -63,4 +62,3 @@ export function updateTextareaValue(dom: HTMLTextAreaElement, props: Props, isIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,22 +19,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { HorizonDom, HorizonSelect, Props } from '../utils/Interface';
|
import { HorizonDom, HorizonSelect, Props } from '../utils/Interface';
|
||||||
import {
|
import { getInputPropsWithoutValue, setInitInputValue, updateInputValue } from './InputValueHandler';
|
||||||
getInputPropsWithoutValue,
|
import { getOptionPropsWithoutValue } from './OptionValueHandler';
|
||||||
setInitInputValue,
|
import { getSelectPropsWithoutValue, updateSelectValue } from './SelectValueHandler';
|
||||||
updateInputValue,
|
import { getTextareaPropsWithoutValue, updateTextareaValue } from './TextareaValueHandler';
|
||||||
} from './InputValueHandler';
|
|
||||||
import {
|
|
||||||
getOptionPropsWithoutValue,
|
|
||||||
} from './OptionValueHandler';
|
|
||||||
import {
|
|
||||||
getSelectPropsWithoutValue,
|
|
||||||
updateSelectValue,
|
|
||||||
} from './SelectValueHandler';
|
|
||||||
import {
|
|
||||||
getTextareaPropsWithoutValue,
|
|
||||||
updateTextareaValue,
|
|
||||||
} from './TextareaValueHandler';
|
|
||||||
|
|
||||||
// 获取元素除了被代理的值以外的属性
|
// 获取元素除了被代理的值以外的属性
|
||||||
function getPropsWithoutValue(type: string, dom: HorizonDom, props: Props) {
|
function getPropsWithoutValue(type: string, dom: HorizonDom, props: Props) {
|
||||||
|
@ -86,8 +74,4 @@ function updateValue(type: string, dom: HorizonDom, props: Props) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { getPropsWithoutValue, setInitValue, updateValue };
|
||||||
getPropsWithoutValue,
|
|
||||||
setInitValue,
|
|
||||||
updateValue,
|
|
||||||
};
|
|
||||||
|
|
|
@ -16,10 +16,7 @@
|
||||||
/**
|
/**
|
||||||
* 事件绑定实现,分为绑定委托事件和非委托事件
|
* 事件绑定实现,分为绑定委托事件和非委托事件
|
||||||
*/
|
*/
|
||||||
import {
|
import { allDelegatedHorizonEvents, allDelegatedNativeEvents } from './EventHub';
|
||||||
allDelegatedHorizonEvents,
|
|
||||||
allDelegatedNativeEvents,
|
|
||||||
} from './EventHub';
|
|
||||||
import { isDocument } from '../dom/utils/Common';
|
import { isDocument } from '../dom/utils/Common';
|
||||||
import { getNearestVNode, getNonDelegatedListenerMap } from '../dom/DOMInternalKeys';
|
import { getNearestVNode, getNonDelegatedListenerMap } from '../dom/DOMInternalKeys';
|
||||||
import { asyncUpdates, runDiscreteUpdates } from '../renderer/TreeBuilder';
|
import { asyncUpdates, runDiscreteUpdates } from '../renderer/TreeBuilder';
|
||||||
|
@ -27,11 +24,7 @@ import { handleEventMain } from './HorizonEventMain';
|
||||||
import { decorateNativeEvent } from './EventWrapper';
|
import { decorateNativeEvent } from './EventWrapper';
|
||||||
import { VNode } from '../renderer/vnode/VNode';
|
import { VNode } from '../renderer/vnode/VNode';
|
||||||
|
|
||||||
const listeningMarker =
|
const listeningMarker = '_horizonListening' + Math.random().toString(36).slice(4);
|
||||||
'_horizonListening' +
|
|
||||||
Math.random()
|
|
||||||
.toString(36)
|
|
||||||
.slice(4);
|
|
||||||
|
|
||||||
// 触发委托事件
|
// 触发委托事件
|
||||||
function triggerDelegatedEvent(
|
function triggerDelegatedEvent(
|
||||||
|
|
|
@ -40,7 +40,7 @@ export class WrappedEvent {
|
||||||
stopPropagation: () => void;
|
stopPropagation: () => void;
|
||||||
preventDefault: () => void;
|
preventDefault: () => void;
|
||||||
|
|
||||||
propagationStopped = false
|
propagationStopped = false;
|
||||||
isPropagationStopped = (): boolean => this.propagationStopped;
|
isPropagationStopped = (): boolean => this.propagationStopped;
|
||||||
|
|
||||||
// 适配Keyboard键盘事件该函数不能由合成事件调用
|
// 适配Keyboard键盘事件该函数不能由合成事件调用
|
||||||
|
@ -53,7 +53,7 @@ export class WrappedEvent {
|
||||||
this[name] = nativeEvent[name];
|
this[name] = nativeEvent[name];
|
||||||
if (name === 'getModifierState') {
|
if (name === 'getModifierState') {
|
||||||
const keyBoardEvent = nativeEvent as KeyboardEvent;
|
const keyBoardEvent = nativeEvent as KeyboardEvent;
|
||||||
this.getModifierState = (keyArg) => keyBoardEvent.getModifierState(keyArg);
|
this.getModifierState = keyArg => keyBoardEvent.getModifierState(keyArg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// stopPropagation和preventDefault 必须通过Event实例调用
|
// stopPropagation和preventDefault 必须通过Event实例调用
|
||||||
|
|
|
@ -87,4 +87,3 @@ function controlInputValue(inputDom: HTMLInputElement, props: Props) {
|
||||||
updateInputValue(inputDom, props);
|
updateInputValue(inputDom, props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -78,11 +78,7 @@ function getChangeListeners(
|
||||||
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
if (shouldTriggerChangeEvent(targetDom, nativeEvtName)) {
|
||||||
recordChangeEventTargets(target);
|
recordChangeEventTargets(target);
|
||||||
|
|
||||||
const event = decorateNativeEvent(
|
const event = decorateNativeEvent('onChange', 'change', nativeEvt);
|
||||||
'onChange',
|
|
||||||
'change',
|
|
||||||
nativeEvt,
|
|
||||||
);
|
|
||||||
return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL);
|
return getListenersFromTree(vNode, 'onChange', event, EVENT_TYPE_ALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +91,7 @@ function getCommonListeners(
|
||||||
vNode: null | VNode,
|
vNode: null | VNode,
|
||||||
nativeEvent: AnyNativeEvent,
|
nativeEvent: AnyNativeEvent,
|
||||||
target: null | EventTarget,
|
target: null | EventTarget,
|
||||||
isCapture: boolean,
|
isCapture: boolean
|
||||||
): ListenerUnitList {
|
): ListenerUnitList {
|
||||||
const horizonEvtName = transformToHorizonEvent(nativeEvtName);
|
const horizonEvtName = transformToHorizonEvent(nativeEvtName);
|
||||||
|
|
||||||
|
@ -117,12 +113,7 @@ function getCommonListeners(
|
||||||
}
|
}
|
||||||
|
|
||||||
const horizonEvent = decorateNativeEvent(horizonEvtName, nativeEvtName, nativeEvent);
|
const horizonEvent = decorateNativeEvent(horizonEvtName, nativeEvtName, nativeEvent);
|
||||||
return getListenersFromTree(
|
return getListenersFromTree(vNode, horizonEvtName, horizonEvent, isCapture ? EVENT_TYPE_CAPTURE : EVENT_TYPE_BUBBLE);
|
||||||
vNode,
|
|
||||||
horizonEvtName,
|
|
||||||
horizonEvent,
|
|
||||||
isCapture ? EVENT_TYPE_CAPTURE : EVENT_TYPE_BUBBLE,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按顺序执行事件队列
|
// 按顺序执行事件队列
|
||||||
|
@ -145,27 +136,16 @@ function triggerHorizonEvents(
|
||||||
nativeEvtName: string,
|
nativeEvtName: string,
|
||||||
isCapture: boolean,
|
isCapture: boolean,
|
||||||
nativeEvent: AnyNativeEvent,
|
nativeEvent: AnyNativeEvent,
|
||||||
vNode: VNode | null,
|
vNode: VNode | null
|
||||||
) {
|
) {
|
||||||
const target = nativeEvent.target || nativeEvent.srcElement!;
|
const target = nativeEvent.target || nativeEvent.srcElement!;
|
||||||
|
|
||||||
// 触发普通委托事件
|
// 触发普通委托事件
|
||||||
let listenerList: ListenerUnitList = getCommonListeners(
|
let listenerList: ListenerUnitList = getCommonListeners(nativeEvtName, vNode, nativeEvent, target, isCapture);
|
||||||
nativeEvtName,
|
|
||||||
vNode,
|
|
||||||
nativeEvent,
|
|
||||||
target,
|
|
||||||
isCapture,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 触发特殊handler委托事件
|
// 触发特殊handler委托事件
|
||||||
if (!isCapture && horizonEventToNativeMap.get('onChange')!.includes(nativeEvtName)) {
|
if (!isCapture && horizonEventToNativeMap.get('onChange')!.includes(nativeEvtName)) {
|
||||||
const changeListeners = getChangeListeners(
|
const changeListeners = getChangeListeners(nativeEvtName, nativeEvent, vNode, target);
|
||||||
nativeEvtName,
|
|
||||||
nativeEvent,
|
|
||||||
vNode,
|
|
||||||
target
|
|
||||||
);
|
|
||||||
if (changeListeners.length) {
|
if (changeListeners.length) {
|
||||||
listenerList = listenerList.concat(changeListeners);
|
listenerList = listenerList.concat(changeListeners);
|
||||||
}
|
}
|
||||||
|
@ -175,7 +155,6 @@ function triggerHorizonEvents(
|
||||||
processListeners(listenerList);
|
processListeners(listenerList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 其他事件正在执行中标记
|
// 其他事件正在执行中标记
|
||||||
let isInEventsExecution = false;
|
let isInEventsExecution = false;
|
||||||
|
|
||||||
|
@ -185,7 +164,7 @@ export function handleEventMain(
|
||||||
isCapture: boolean,
|
isCapture: boolean,
|
||||||
nativeEvent: AnyNativeEvent,
|
nativeEvent: AnyNativeEvent,
|
||||||
vNode: null | VNode,
|
vNode: null | VNode,
|
||||||
targetDom: EventTarget,
|
targetDom: EventTarget
|
||||||
): void {
|
): void {
|
||||||
let startVNode = vNode;
|
let startVNode = vNode;
|
||||||
if (startVNode !== null) {
|
if (startVNode !== null) {
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||||
*
|
*
|
||||||
|
@ -16,7 +15,6 @@
|
||||||
|
|
||||||
export function isInputElement(dom?: HTMLElement): boolean {
|
export function isInputElement(dom?: HTMLElement): boolean {
|
||||||
return dom instanceof HTMLInputElement || dom instanceof HTMLTextAreaElement;
|
return dom instanceof HTMLInputElement || dom instanceof HTMLTextAreaElement;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setPropertyWritable(obj, propName) {
|
export function setPropertyWritable(obj, propName) {
|
||||||
|
|
|
@ -56,8 +56,8 @@ function mergeDefault(sourceObj, defaultObj) {
|
||||||
|
|
||||||
function buildElement(isClone, type, setting, children) {
|
function buildElement(isClone, type, setting, children) {
|
||||||
// setting中的值优先级最高,clone情况下从 type 中取值,创建情况下直接赋值为 null
|
// setting中的值优先级最高,clone情况下从 type 中取值,创建情况下直接赋值为 null
|
||||||
const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null);
|
const key = setting && setting.key !== undefined ? String(setting.key) : isClone ? type.key : null;
|
||||||
const ref = (setting && setting.ref !== undefined) ? setting.ref : (isClone ? type.ref : null);
|
const ref = setting && setting.ref !== undefined ? setting.ref : isClone ? type.ref : null;
|
||||||
const props = isClone ? { ...type.props } : {};
|
const props = isClone ? { ...type.props } : {};
|
||||||
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
|
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
|
||||||
|
|
||||||
|
|
|
@ -54,7 +54,7 @@ export const helper = {
|
||||||
return { name: HookName.RefHook, hIndex, value: (state as Ref<any>).current };
|
return { name: HookName.RefHook, hIndex, value: (state as Ref<any>).current };
|
||||||
} else if (isEffectHook(state)) {
|
} else if (isEffectHook(state)) {
|
||||||
const name =
|
const name =
|
||||||
state.effectConstant == EffectConstant.LayoutEffect || (EffectConstant.LayoutEffect | EffectConstant.DepsChange)
|
state.effectConstant == EffectConstant.LayoutEffect || EffectConstant.LayoutEffect | EffectConstant.DepsChange
|
||||||
? HookName.LayoutEffectHook
|
? HookName.LayoutEffectHook
|
||||||
: HookName.EffectHook;
|
: HookName.EffectHook;
|
||||||
return { name, hIndex, value: (state as Effect).effect };
|
return { name, hIndex, value: (state as Effect).effect };
|
||||||
|
|
|
@ -19,7 +19,7 @@ import { createContext } from '../../renderer/components/context/CreateContext';
|
||||||
import { createElement } from '../../external/JSXElement';
|
import { createElement } from '../../external/JSXElement';
|
||||||
import { BoundActionCreator } from './redux';
|
import { BoundActionCreator } from './redux';
|
||||||
import { ReduxAction } from './redux';
|
import { ReduxAction } from './redux';
|
||||||
import { ReduxStoreHandler } from '../store/StoreHandler'
|
import { ReduxStoreHandler } from '../store/StoreHandler';
|
||||||
|
|
||||||
const DefaultContext = createContext(null);
|
const DefaultContext = createContext(null);
|
||||||
type Context = typeof DefaultContext;
|
type Context = typeof DefaultContext;
|
||||||
|
@ -44,7 +44,7 @@ export function createStoreHook(context: Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createSelectorHook(context: Context): (selector?: (any) => any) => any {
|
export function createSelectorHook(context: Context): (selector?: (any) => any) => any {
|
||||||
const store = (createStoreHook(context)() as unknown) as ReduxStoreHandler;
|
const store = createStoreHook(context)() as unknown as ReduxStoreHandler;
|
||||||
return function (selector = state => state) {
|
return function (selector = state => state) {
|
||||||
const [b, fr] = useState(false);
|
const [b, fr] = useState(false);
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ export function createSelectorHook(context: Context): (selector?: (any) => any)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createDispatchHook(context: Context): () => BoundActionCreator {
|
export function createDispatchHook(context: Context): () => BoundActionCreator {
|
||||||
const store = (createStoreHook(context)() as unknown) as ReduxStoreHandler;
|
const store = createStoreHook(context)() as unknown as ReduxStoreHandler;
|
||||||
return function () {
|
return function () {
|
||||||
return action => {
|
return action => {
|
||||||
store.dispatch(action);
|
store.dispatch(action);
|
||||||
|
@ -120,7 +120,7 @@ export function connect(
|
||||||
function Wrapper(props) {
|
function Wrapper(props) {
|
||||||
const [f, forceReload] = useState(true);
|
const [f, forceReload] = useState(true);
|
||||||
|
|
||||||
const store = (useStore() as unknown) as ReduxStoreHandler;
|
const store = useStore() as unknown as ReduxStoreHandler;
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unsubscribe = store.subscribe(() => forceReload(!f));
|
const unsubscribe = store.subscribe(() => forceReload(!f));
|
||||||
|
|
|
@ -17,7 +17,9 @@ import { ReduxAction, ReduxMiddleware } from './redux';
|
||||||
import { ReduxStoreHandler } from '../store/StoreHandler';
|
import { ReduxStoreHandler } from '../store/StoreHandler';
|
||||||
|
|
||||||
function createThunkMiddleware(extraArgument?: any): ReduxMiddleware {
|
function createThunkMiddleware(extraArgument?: any): ReduxMiddleware {
|
||||||
return (store: ReduxStoreHandler) => (next: (action: ReduxAction) => any) => (
|
return (store: ReduxStoreHandler) =>
|
||||||
|
(next: (action: ReduxAction) => any) =>
|
||||||
|
(
|
||||||
action:
|
action:
|
||||||
| ReduxAction
|
| ReduxAction
|
||||||
| ((dispatch: (action: ReduxAction) => void, store: ReduxStoreHandler, extraArgument?: any) => any)
|
| ((dispatch: (action: ReduxAction) => void, store: ReduxStoreHandler, extraArgument?: any) => any)
|
||||||
|
|
|
@ -17,13 +17,12 @@ import {IObserver} from './Observer';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 一个对象(对象、数组、集合)对应一个Observer
|
* 一个对象(对象、数组、集合)对应一个Observer
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
export class HooklessObserver implements IObserver {
|
export class HooklessObserver implements IObserver {
|
||||||
|
|
||||||
listeners: (() => void)[] = [];
|
listeners: (() => void)[] = [];
|
||||||
|
|
||||||
useProp(key: string | symbol): void {
|
useProp(key: string | symbol): void {}
|
||||||
}
|
|
||||||
|
|
||||||
addListener(listener: () => void) {
|
addListener(listener: () => void) {
|
||||||
this.listeners.push(listener);
|
this.listeners.push(listener);
|
||||||
|
@ -46,12 +45,9 @@ export class HooklessObserver implements IObserver {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
triggerUpdate(vNode): void {
|
triggerUpdate(vNode): void {}
|
||||||
}
|
|
||||||
|
|
||||||
allChange(): void {
|
allChange(): void {}
|
||||||
}
|
|
||||||
|
|
||||||
clearByVNode(vNode): void {
|
clearByVNode(vNode): void {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -109,7 +109,7 @@ export class Observer implements IObserver {
|
||||||
}
|
}
|
||||||
|
|
||||||
allChange(): void {
|
allChange(): void {
|
||||||
let keyIt = this.keyVNodes.keys();
|
const keyIt = this.keyVNodes.keys();
|
||||||
let keyItem = keyIt.next();
|
let keyItem = keyIt.next();
|
||||||
while (!keyItem.done) {
|
while (!keyItem.done) {
|
||||||
this.setProp(keyItem.value);
|
this.setProp(keyItem.value);
|
||||||
|
|
|
@ -42,8 +42,8 @@ export function get(rawObj: object, key: string | symbol, receiver: any, singleL
|
||||||
observer.watchers[prop].push(handler);
|
observer.watchers[prop].push(handler);
|
||||||
return () => {
|
return () => {
|
||||||
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
|
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key === 'addListener') {
|
if (key === 'addListener') {
|
||||||
|
|
|
@ -14,7 +14,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export interface IObserver {
|
export interface IObserver {
|
||||||
|
|
||||||
useProp: (key: string | symbol) => void;
|
useProp: (key: string | symbol) => void;
|
||||||
|
|
||||||
addListener: (listener: () => void) => void;
|
addListener: (listener: () => void) => void;
|
||||||
|
|
|
@ -38,18 +38,13 @@ function consoleError(error: any): void {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleRootError(
|
function handleRootError(error: any) {
|
||||||
error: any,
|
|
||||||
) {
|
|
||||||
// 注意:如果根节点抛出错误,不会销毁整棵树,只打印日志,抛出异常。
|
// 注意:如果根节点抛出错误,不会销毁整棵树,只打印日志,抛出异常。
|
||||||
setRootThrowError(error);
|
setRootThrowError(error);
|
||||||
consoleError(error);
|
consoleError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
function createClassErrorUpdate(
|
function createClassErrorUpdate(vNode: VNode, error: any): Update {
|
||||||
vNode: VNode,
|
|
||||||
error: any,
|
|
||||||
): Update {
|
|
||||||
const update = newUpdate();
|
const update = newUpdate();
|
||||||
update.type = UpdateState.Error;
|
update.type = UpdateState.Error;
|
||||||
|
|
||||||
|
@ -78,13 +73,10 @@ function createClassErrorUpdate(
|
||||||
return update;
|
return update;
|
||||||
}
|
}
|
||||||
function isPromise(error: any): error is PromiseType<any> {
|
function isPromise(error: any): error is PromiseType<any> {
|
||||||
return error !== null && typeof error === 'object' && typeof error.then === 'function'
|
return error !== null && typeof error === 'object' && typeof error.then === 'function';
|
||||||
}
|
}
|
||||||
// 处理capture和bubble阶段抛出的错误
|
// 处理capture和bubble阶段抛出的错误
|
||||||
export function handleRenderThrowError(
|
export function handleRenderThrowError(sourceVNode: VNode, error: any) {
|
||||||
sourceVNode: VNode,
|
|
||||||
error: any,
|
|
||||||
) {
|
|
||||||
// vNode抛出了异常,标记Interrupted中断
|
// vNode抛出了异常,标记Interrupted中断
|
||||||
FlagUtils.markInterrupted(sourceVNode);
|
FlagUtils.markInterrupted(sourceVNode);
|
||||||
// dirtyNodes 不再有效
|
// dirtyNodes 不再有效
|
||||||
|
@ -117,10 +109,8 @@ export function handleRenderThrowError(
|
||||||
const instance = vNode.realNode;
|
const instance = vNode.realNode;
|
||||||
if (
|
if (
|
||||||
(vNode.flags & DidCapture) === InitFlag &&
|
(vNode.flags & DidCapture) === InitFlag &&
|
||||||
(
|
(typeof ctor.getDerivedStateFromError === 'function' ||
|
||||||
typeof ctor.getDerivedStateFromError === 'function' ||
|
(instance !== null && typeof instance.componentDidCatch === 'function'))
|
||||||
(instance !== null && typeof instance.componentDidCatch === 'function')
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
FlagUtils.markShouldCapture(vNode);
|
FlagUtils.markShouldCapture(vNode);
|
||||||
|
|
||||||
|
@ -155,7 +145,6 @@ function triggerUpdate(vNode, state) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 处理submit阶段的异常
|
// 处理submit阶段的异常
|
||||||
export function handleSubmitError(vNode: VNode, error: any) {
|
export function handleSubmitError(vNode: VNode, error: any) {
|
||||||
if (vNode.tag === TreeRoot) {
|
if (vNode.tag === TreeRoot) {
|
||||||
|
@ -169,20 +158,19 @@ export function handleSubmitError(vNode: VNode, error: any) {
|
||||||
if (node.tag === TreeRoot) {
|
if (node.tag === TreeRoot) {
|
||||||
handleRootError(error);
|
handleRootError(error);
|
||||||
return;
|
return;
|
||||||
} else if (node.tag === ClassComponent) { // 只有 class 组件才可以成为错误边界组件
|
} else if (node.tag === ClassComponent) {
|
||||||
|
// 只有 class 组件才可以成为错误边界组件
|
||||||
const ctor = node.type;
|
const ctor = node.type;
|
||||||
const instance = node.realNode;
|
const instance = node.realNode;
|
||||||
if (
|
if (typeof ctor.getDerivedStateFromError === 'function' || typeof instance.componentDidCatch === 'function') {
|
||||||
typeof ctor.getDerivedStateFromError === 'function' ||
|
|
||||||
typeof instance.componentDidCatch === 'function'
|
|
||||||
) {
|
|
||||||
const getDerivedStateFromError = node.type.getDerivedStateFromError;
|
const getDerivedStateFromError = node.type.getDerivedStateFromError;
|
||||||
if (typeof getDerivedStateFromError === 'function') {
|
if (typeof getDerivedStateFromError === 'function') {
|
||||||
// 打印错误
|
// 打印错误
|
||||||
consoleError(error);
|
consoleError(error);
|
||||||
|
|
||||||
const retState = getDerivedStateFromError(error);
|
const retState = getDerivedStateFromError(error);
|
||||||
if (retState) { // 有返回值
|
if (retState) {
|
||||||
|
// 有返回值
|
||||||
// 触发更新
|
// 触发更新
|
||||||
triggerUpdate(node, retState);
|
triggerUpdate(node, retState);
|
||||||
}
|
}
|
||||||
|
@ -190,7 +178,8 @@ export function handleSubmitError(vNode: VNode, error: any) {
|
||||||
|
|
||||||
// 处理componentDidCatch
|
// 处理componentDidCatch
|
||||||
if (instance !== null && typeof instance.componentDidCatch === 'function') {
|
if (instance !== null && typeof instance.componentDidCatch === 'function') {
|
||||||
if (typeof getDerivedStateFromError !== 'function') { // 没有getDerivedStateFromError
|
if (typeof getDerivedStateFromError !== 'function') {
|
||||||
|
// 没有getDerivedStateFromError
|
||||||
// 打印错误
|
// 打印错误
|
||||||
consoleError(error);
|
consoleError(error);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||||
*
|
*
|
||||||
|
|
|
@ -16,30 +16,15 @@
|
||||||
import type { VNode } from './Types';
|
import type { VNode } from './Types';
|
||||||
import type { Update } from './UpdateHandler';
|
import type { Update } from './UpdateHandler';
|
||||||
|
|
||||||
import {
|
import { asyncUpdates, syncUpdates, runDiscreteUpdates, launchUpdateFromVNode } from './TreeBuilder';
|
||||||
asyncUpdates,
|
|
||||||
syncUpdates,
|
|
||||||
runDiscreteUpdates,
|
|
||||||
launchUpdateFromVNode,
|
|
||||||
} from './TreeBuilder';
|
|
||||||
import { runAsyncEffects } from './submit/HookEffectHandler';
|
import { runAsyncEffects } from './submit/HookEffectHandler';
|
||||||
import { Callback, newUpdate, pushUpdate } from './UpdateHandler';
|
import { Callback, newUpdate, pushUpdate } from './UpdateHandler';
|
||||||
|
|
||||||
|
|
||||||
export { createVNode, createTreeRootVNode } from './vnode/VNodeCreator';
|
export { createVNode, createTreeRootVNode } from './vnode/VNodeCreator';
|
||||||
export { createPortal } from './components/CreatePortal';
|
export { createPortal } from './components/CreatePortal';
|
||||||
export {
|
export { asyncUpdates, syncUpdates, runDiscreteUpdates, runAsyncEffects };
|
||||||
asyncUpdates,
|
|
||||||
syncUpdates,
|
|
||||||
runDiscreteUpdates,
|
|
||||||
runAsyncEffects,
|
|
||||||
};
|
|
||||||
|
|
||||||
export function startUpdate(
|
export function startUpdate(element: any, treeRoot: VNode, callback?: Callback) {
|
||||||
element: any,
|
|
||||||
treeRoot: VNode,
|
|
||||||
callback?: Callback,
|
|
||||||
) {
|
|
||||||
const update: Update = newUpdate();
|
const update: Update = newUpdate();
|
||||||
update.content = { element };
|
update.content = { element };
|
||||||
|
|
||||||
|
@ -58,4 +43,3 @@ export function getFirstCustomDom(treeRoot?: VNode | null): Element | Text | nul
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,12 +45,7 @@ import {
|
||||||
isExecuting,
|
isExecuting,
|
||||||
setExecuteMode,
|
setExecuteMode,
|
||||||
} from './ExecuteMode';
|
} from './ExecuteMode';
|
||||||
import {
|
import { resetContext, resetNamespaceCtx, setContext, setNamespaceCtx } from './ContextSaver';
|
||||||
resetContext,
|
|
||||||
resetNamespaceCtx,
|
|
||||||
setContext,
|
|
||||||
setNamespaceCtx,
|
|
||||||
} from './ContextSaver';
|
|
||||||
import {
|
import {
|
||||||
updateChildShouldUpdate,
|
updateChildShouldUpdate,
|
||||||
updateParentsChildShouldUpdate,
|
updateParentsChildShouldUpdate,
|
||||||
|
@ -110,7 +105,8 @@ function bubbleVNode(vNode: VNode): void {
|
||||||
do {
|
do {
|
||||||
const parent = node.parent;
|
const parent = node.parent;
|
||||||
|
|
||||||
if ((node.flags & Interrupted) === InitFlag) { // vNode没有抛出异常
|
if ((node.flags & Interrupted) === InitFlag) {
|
||||||
|
// vNode没有抛出异常
|
||||||
componentRenders[node.tag].bubbleRender(node);
|
componentRenders[node.tag].bubbleRender(node);
|
||||||
|
|
||||||
// 设置node的childShouldUpdate属性
|
// 设置node的childShouldUpdate属性
|
||||||
|
@ -133,7 +129,8 @@ function bubbleVNode(vNode: VNode): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
const siblingVNode = node.next;
|
const siblingVNode = node.next;
|
||||||
if (siblingVNode !== null) { // 有兄弟vNode
|
if (siblingVNode !== null) {
|
||||||
|
// 有兄弟vNode
|
||||||
processing = siblingVNode;
|
processing = siblingVNode;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -244,7 +241,8 @@ function buildVNodeTree(treeRoot: VNode) {
|
||||||
// 清空toUpdateNodes
|
// 清空toUpdateNodes
|
||||||
treeRoot.toUpdateNodes.clear();
|
treeRoot.toUpdateNodes.clear();
|
||||||
|
|
||||||
if (startVNode.tag !== TreeRoot) { // 不是根节点
|
if (startVNode.tag !== TreeRoot) {
|
||||||
|
// 不是根节点
|
||||||
// 设置namespace,用于createElement
|
// 设置namespace,用于createElement
|
||||||
let parent = startVNode.parent;
|
let parent = startVNode.parent;
|
||||||
while (parent !== null) {
|
while (parent !== null) {
|
||||||
|
@ -290,7 +288,8 @@ function buildVNodeTree(treeRoot: VNode) {
|
||||||
handleError(treeRoot, thrownValue);
|
handleError(treeRoot, thrownValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (startVNode.tag !== TreeRoot) { // 不是根节点
|
if (startVNode.tag !== TreeRoot) {
|
||||||
|
// 不是根节点
|
||||||
// 恢复父节点的context
|
// 恢复父节点的context
|
||||||
resetTreeContext(startVNode);
|
resetTreeContext(startVNode);
|
||||||
}
|
}
|
||||||
|
@ -365,9 +364,7 @@ function renderFromRoot(treeRoot) {
|
||||||
export function tryRenderFromRoot(treeRoot: VNode) {
|
export function tryRenderFromRoot(treeRoot: VNode) {
|
||||||
if (treeRoot.shouldUpdate && treeRoot.task === null) {
|
if (treeRoot.shouldUpdate && treeRoot.task === null) {
|
||||||
// 任务放进queue,但是调度开始还是异步的
|
// 任务放进queue,但是调度开始还是异步的
|
||||||
treeRoot.task = pushRenderCallback(
|
treeRoot.task = pushRenderCallback(renderFromRoot.bind(null, treeRoot));
|
||||||
renderFromRoot.bind(null, treeRoot),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,8 +384,11 @@ export function launchUpdateFromVNode(vNode: VNode) {
|
||||||
// 保存待刷新的节点
|
// 保存待刷新的节点
|
||||||
treeRoot.toUpdateNodes?.add(vNode);
|
treeRoot.toUpdateNodes?.add(vNode);
|
||||||
|
|
||||||
if (checkMode(BySync) && // 非批量
|
if (
|
||||||
!checkMode(InRender)) { // 不是渲染阶段触发
|
checkMode(BySync) && // 非批量
|
||||||
|
!checkMode(InRender)
|
||||||
|
) {
|
||||||
|
// 不是渲染阶段触发
|
||||||
|
|
||||||
// 业务直接调用Horizon.render的时候会进入这个分支,同步渲染。
|
// 业务直接调用Horizon.render的时候会进入这个分支,同步渲染。
|
||||||
// 不能改成下面的异步,否则会有时序问题,因为业务可能会依赖这个渲染的完成。
|
// 不能改成下面的异步,否则会有时序问题,因为业务可能会依赖这个渲染的完成。
|
||||||
|
|
|
@ -53,13 +53,7 @@ export function pushUpdate(vNode: VNode, update: Update) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 根据update获取新的state
|
// 根据update获取新的state
|
||||||
function calcState(
|
function calcState(vNode: VNode, update: Update, inst: any, oldState: any, props: any): any {
|
||||||
vNode: VNode,
|
|
||||||
update: Update,
|
|
||||||
inst: any,
|
|
||||||
oldState: any,
|
|
||||||
props: any,
|
|
||||||
): any {
|
|
||||||
switch (update.type) {
|
switch (update.type) {
|
||||||
case UpdateState.Override:
|
case UpdateState.Override:
|
||||||
const content = update.content;
|
const content = update.content;
|
||||||
|
@ -73,9 +67,7 @@ function calcState(
|
||||||
case UpdateState.Update:
|
case UpdateState.Update:
|
||||||
const updateContent = update.content;
|
const updateContent = update.content;
|
||||||
const newState = typeof updateContent === 'function' ? updateContent.call(inst, oldState, props) : updateContent;
|
const newState = typeof updateContent === 'function' ? updateContent.call(inst, oldState, props) : updateContent;
|
||||||
return (newState === null || newState === undefined)
|
return newState === null || newState === undefined ? oldState : { ...oldState, ...newState };
|
||||||
? oldState
|
|
||||||
: { ...oldState, ...newState };
|
|
||||||
default:
|
default:
|
||||||
return oldState;
|
return oldState;
|
||||||
}
|
}
|
||||||
|
@ -118,7 +110,6 @@ export function processUpdates(vNode: VNode, inst: any, props: any): void {
|
||||||
calcUpdates(vNode, props, inst, toProcessUpdates);
|
calcUpdates(vNode, props, inst, toProcessUpdates);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function pushForceUpdate(vNode: VNode) {
|
export function pushForceUpdate(vNode: VNode) {
|
||||||
|
|
|
@ -16,11 +16,7 @@
|
||||||
import { TYPE_PORTAL } from '../../external/JSXElementType';
|
import { TYPE_PORTAL } from '../../external/JSXElementType';
|
||||||
import type { PortalType } from '../Types';
|
import type { PortalType } from '../Types';
|
||||||
|
|
||||||
export function createPortal(
|
export function createPortal(children: any, realNode: any, key = ''): PortalType {
|
||||||
children: any,
|
|
||||||
realNode: any,
|
|
||||||
key: string = '',
|
|
||||||
): PortalType {
|
|
||||||
return {
|
return {
|
||||||
vtype: TYPE_PORTAL,
|
vtype: TYPE_PORTAL,
|
||||||
key: key == '' ? '' : '' + key,
|
key: key == '' ? '' : '' + key,
|
||||||
|
|
|
@ -59,7 +59,7 @@ function lazyLoader<T>(lazyContent: LazyContent<T>): any {
|
||||||
lazyContent._status = LayStatus.Rejected;
|
lazyContent._status = LayStatus.Rejected;
|
||||||
lazyContent._value = error;
|
lazyContent._value = error;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (lazyContent._status === LayStatus.Fulfilled) {
|
if (lazyContent._status === LayStatus.Fulfilled) {
|
||||||
|
|
|
@ -35,7 +35,7 @@ function collectDeps<T>(vNode: VNode, context: ContextType<T>) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNewContext<T>(vNode: VNode, ctx: ContextType<T>, isUseContext: boolean = false): T {
|
export function getNewContext<T>(vNode: VNode, ctx: ContextType<T>, isUseContext = false): T {
|
||||||
// 如果来自于useContext,则需要在函数组件中调用
|
// 如果来自于useContext,则需要在函数组件中调用
|
||||||
if (isUseContext && getHookStage() === null) {
|
if (isUseContext && getHookStage() === null) {
|
||||||
throwNotInFuncError();
|
throwNotInFuncError();
|
||||||
|
|
|
@ -24,13 +24,7 @@ import {
|
||||||
createPortalVNode,
|
createPortalVNode,
|
||||||
createDomTextVNode,
|
createDomTextVNode,
|
||||||
} from '../vnode/VNodeCreator';
|
} from '../vnode/VNodeCreator';
|
||||||
import {
|
import { isSameType, getIteratorFn, isTextType, isIteratorType, isObjectType } from './DiffTools';
|
||||||
isSameType,
|
|
||||||
getIteratorFn,
|
|
||||||
isTextType,
|
|
||||||
isIteratorType,
|
|
||||||
isObjectType,
|
|
||||||
} from './DiffTools';
|
|
||||||
import { travelChildren } from '../vnode/VNodeUtils';
|
import { travelChildren } from '../vnode/VNodeUtils';
|
||||||
import { markVNodePath } from '../utils/vNodePath';
|
import { markVNodePath } from '../utils/vNodePath';
|
||||||
|
|
||||||
|
@ -120,10 +114,12 @@ function getNodeType(newChild: any): string | null {
|
||||||
function setVNodeAdditionFlag(newNode: VNode, lastPosition: number): number {
|
function setVNodeAdditionFlag(newNode: VNode, lastPosition: number): number {
|
||||||
let position = lastPosition;
|
let position = lastPosition;
|
||||||
|
|
||||||
if (newNode.isCreated || newNode.eIndex < lastPosition) { // 位置 小于 上一个复用的位置
|
if (newNode.isCreated || newNode.eIndex < lastPosition) {
|
||||||
|
// 位置 小于 上一个复用的位置
|
||||||
// 标记为新增
|
// 标记为新增
|
||||||
FlagUtils.setAddition(newNode);
|
FlagUtils.setAddition(newNode);
|
||||||
} else { // 复用
|
} else {
|
||||||
|
// 复用
|
||||||
position = newNode.eIndex;
|
position = newNode.eIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,15 +202,16 @@ function transRightChildrenToArray(child) {
|
||||||
return rightChildrenArray;
|
return rightChildrenArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
function transLeftChildrenToMap(
|
function transLeftChildrenToMap(startChild: VNode, rightEndVNode: VNode | null): Map<string | number, VNode> {
|
||||||
startChild: VNode,
|
|
||||||
rightEndVNode: VNode | null,
|
|
||||||
): Map<string | number, VNode> {
|
|
||||||
const leftChildrenMap: Map<string | number, VNode> = new Map();
|
const leftChildrenMap: Map<string | number, VNode> = new Map();
|
||||||
|
|
||||||
travelChildren(startChild, node => {
|
travelChildren(
|
||||||
|
startChild,
|
||||||
|
node => {
|
||||||
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
|
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
|
||||||
}, node => node === rightEndVNode);
|
},
|
||||||
|
node => node === rightEndVNode
|
||||||
|
);
|
||||||
|
|
||||||
return leftChildrenMap;
|
return leftChildrenMap;
|
||||||
}
|
}
|
||||||
|
@ -235,11 +232,7 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff数组类型的节点,核心算法
|
// diff数组类型的节点,核心算法
|
||||||
function diffArrayNodesHandler(
|
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
|
||||||
parentNode: VNode,
|
|
||||||
firstChild: VNode | null,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
): VNode | null {
|
|
||||||
let resultingFirstChild: VNode | null = null;
|
let resultingFirstChild: VNode | null = null;
|
||||||
|
|
||||||
let prevNewNode: VNode | null = null;
|
let prevNewNode: VNode | null = null;
|
||||||
|
@ -366,13 +359,14 @@ function diffArrayNodesHandler(
|
||||||
|
|
||||||
// 4. 新节点还有一部分,但是老节点已经没有了
|
// 4. 新节点还有一部分,但是老节点已经没有了
|
||||||
if (oldNode === null) {
|
if (oldNode === null) {
|
||||||
|
|
||||||
let isDirectAdd = false;
|
let isDirectAdd = false;
|
||||||
// TODO: 是否可以扩大至非dom类型节点
|
// TODO: 是否可以扩大至非dom类型节点
|
||||||
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
// 如果dom节点在上次添加前没有节点,说明本次添加时,可以直接添加到最后,不需要通过 getSiblingDom 函数找到 before 节点
|
||||||
if (parentNode.tag === DomComponent &&
|
if (
|
||||||
|
parentNode.tag === DomComponent &&
|
||||||
parentNode.oldProps?.children?.length === 0 &&
|
parentNode.oldProps?.children?.length === 0 &&
|
||||||
rightIdx - leftIdx === newChildren.length) {
|
rightIdx - leftIdx === newChildren.length
|
||||||
|
) {
|
||||||
isDirectAdd = true;
|
isDirectAdd = true;
|
||||||
}
|
}
|
||||||
const isAddition = parentNode.tag === DomPortal || !parentNode.isCreated;
|
const isAddition = parentNode.tag === DomPortal || !parentNode.isCreated;
|
||||||
|
@ -424,7 +418,8 @@ function diffArrayNodesHandler(
|
||||||
const eIndex = newNode.eIndex;
|
const eIndex = newNode.eIndex;
|
||||||
eIndexes.push(eIndex);
|
eIndexes.push(eIndex);
|
||||||
last = eIndexes[result[result.length - 1]];
|
last = eIndexes[result[result.length - 1]];
|
||||||
if (eIndex > last || last === undefined) { // 大的 eIndex直接放在最后
|
if (eIndex > last || last === undefined) {
|
||||||
|
// 大的 eIndex直接放在最后
|
||||||
preIndex[i] = result[result.length - 1];
|
preIndex[i] = result[result.length - 1];
|
||||||
result.push(i);
|
result.push(i);
|
||||||
} else {
|
} else {
|
||||||
|
@ -500,7 +495,7 @@ function setVNodesCIndex(startChild: VNode | null, startIdx: number) {
|
||||||
function diffIteratorNodesHandler(
|
function diffIteratorNodesHandler(
|
||||||
parentNode: VNode,
|
parentNode: VNode,
|
||||||
firstChild: VNode | null,
|
firstChild: VNode | null,
|
||||||
newChildrenIterable: Iterable<any>,
|
newChildrenIterable: Iterable<any>
|
||||||
): VNode | null {
|
): VNode | null {
|
||||||
const iteratorFn = getIteratorFn(newChildrenIterable);
|
const iteratorFn = getIteratorFn(newChildrenIterable);
|
||||||
const iteratorObj = iteratorFn.call(newChildrenIterable);
|
const iteratorObj = iteratorFn.call(newChildrenIterable);
|
||||||
|
@ -517,12 +512,7 @@ function diffIteratorNodesHandler(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新节点是字符串类型
|
// 新节点是字符串类型
|
||||||
function diffStringNodeHandler(
|
function diffStringNodeHandler(parentNode: VNode, newChild: any, firstChildVNode: VNode, isComparing: boolean) {
|
||||||
parentNode: VNode,
|
|
||||||
newChild: any,
|
|
||||||
firstChildVNode: VNode,
|
|
||||||
isComparing: boolean
|
|
||||||
) {
|
|
||||||
let newTextNode: VNode | null = null;
|
let newTextNode: VNode | null = null;
|
||||||
|
|
||||||
// 第一个vNode是Text,则复用
|
// 第一个vNode是Text,则复用
|
||||||
|
|
|
@ -35,9 +35,7 @@ export function setCurrentHook(hook: Hook<any, any> | null) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function throwNotInFuncError() {
|
export function throwNotInFuncError() {
|
||||||
throw Error(
|
throw Error('Hooks should be used inside function component.');
|
||||||
'Hooks should be used inside function component.',
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新建一个hook,并放到vNode.hooks中
|
// 新建一个hook,并放到vNode.hooks中
|
||||||
|
@ -63,9 +61,8 @@ export function getNextHook(hook: Hook<any, any>, hooks: Array<Hook<any, any>>)
|
||||||
// 原因:1.比对hook的数量有没有变化(非必要);2.从上一次执行中的hook获取removeEffect
|
// 原因:1.比对hook的数量有没有变化(非必要);2.从上一次执行中的hook获取removeEffect
|
||||||
export function getCurrentHook(): Hook<any, any> {
|
export function getCurrentHook(): Hook<any, any> {
|
||||||
const processingVNode = getProcessingVNode();
|
const processingVNode = getProcessingVNode();
|
||||||
currentHook = currentHook !== null ?
|
currentHook =
|
||||||
getNextHook(currentHook, processingVNode.hooks) :
|
currentHook !== null ? getNextHook(currentHook, processingVNode.hooks) : processingVNode.hooks[0] || null;
|
||||||
(processingVNode.hooks[0] || null);
|
|
||||||
|
|
||||||
if (lastTimeHook !== null) {
|
if (lastTimeHook !== null) {
|
||||||
lastTimeHook = getNextHook(lastTimeHook, processingVNode.oldHooks);
|
lastTimeHook = getNextHook(lastTimeHook, processingVNode.oldHooks);
|
||||||
|
|
|
@ -29,23 +29,16 @@ import {Ref, Trigger} from './HookType';
|
||||||
type BasicStateAction<S> = ((S) => S) | S;
|
type BasicStateAction<S> = ((S) => S) | S;
|
||||||
type Dispatch<A> = (A) => void;
|
type Dispatch<A> = (A) => void;
|
||||||
|
|
||||||
|
export function useContext<T>(Context: ContextType<T>): T {
|
||||||
export function useContext<T>(
|
|
||||||
Context: ContextType<T>,
|
|
||||||
): T {
|
|
||||||
const processingVNode = getProcessingVNode();
|
const processingVNode = getProcessingVNode();
|
||||||
return getNewContext(processingVNode!, Context, true);
|
return getNewContext(processingVNode!, Context, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useState<S>(initialState: (() => S) | S,): [S, Dispatch<BasicStateAction<S>>] {
|
export function useState<S>(initialState: (() => S) | S): [S, Dispatch<BasicStateAction<S>>] {
|
||||||
return useStateImpl(initialState);
|
return useStateImpl(initialState);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useReducer<S, I, A>(
|
export function useReducer<S, I, A>(reducer: (S, A) => S, initialArg: I, init?: (I) => S): [S, Trigger<A>] | void {
|
||||||
reducer: (S, A) => S,
|
|
||||||
initialArg: I,
|
|
||||||
init?: (I) => S,
|
|
||||||
): [S, Trigger<A>] | void {
|
|
||||||
return useReducerImpl(reducer, initialArg, init);
|
return useReducerImpl(reducer, initialArg, init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,38 +46,26 @@ export function useRef<T>(initialValue: T): Ref<T> {
|
||||||
return useRefImpl(initialValue);
|
return useRefImpl(initialValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useEffect(
|
export function useEffect(create: () => (() => void) | void, deps?: Array<any> | null): void {
|
||||||
create: () => (() => void) | void,
|
|
||||||
deps?: Array<any> | null,
|
|
||||||
): void {
|
|
||||||
return useEffectImpl(create, deps);
|
return useEffectImpl(create, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLayoutEffect(
|
export function useLayoutEffect(create: () => (() => void) | void, deps?: Array<any> | null): void {
|
||||||
create: () => (() => void) | void,
|
|
||||||
deps?: Array<any> | null,
|
|
||||||
): void {
|
|
||||||
return useLayoutEffectImpl(create, deps);
|
return useLayoutEffectImpl(create, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useCallback<T>(
|
export function useCallback<T>(callback: T, deps?: Array<any> | null): T {
|
||||||
callback: T,
|
|
||||||
deps?: Array<any> | null,
|
|
||||||
): T {
|
|
||||||
return useCallbackImpl(callback, deps);
|
return useCallbackImpl(callback, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useMemo<T>(
|
export function useMemo<T>(create: () => T, deps?: Array<any> | null): T {
|
||||||
create: () => T,
|
|
||||||
deps?: Array<any> | null,
|
|
||||||
): T {
|
|
||||||
return useMemoImpl(create, deps);
|
return useMemoImpl(create, deps);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useImperativeHandle<T>(
|
export function useImperativeHandle<T>(
|
||||||
ref: { current: T | null } | ((inst: T | null) => any) | null | void,
|
ref: { current: T | null } | ((inst: T | null) => any) | null | void,
|
||||||
create: () => T,
|
create: () => T,
|
||||||
deps?: Array<any> | null,
|
deps?: Array<any> | null
|
||||||
): void {
|
): void {
|
||||||
return useImperativeHandleImpl(ref, create, deps);
|
return useImperativeHandleImpl(ref, create, deps);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,7 @@
|
||||||
|
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
|
|
||||||
import {
|
import { getLastTimeHook, setLastTimeHook, setCurrentHook, getNextHook } from './BaseHook';
|
||||||
getLastTimeHook,
|
|
||||||
setLastTimeHook,
|
|
||||||
setCurrentHook, getNextHook
|
|
||||||
} from './BaseHook';
|
|
||||||
import { HookStage, setHookStage } from './HookStage';
|
import { HookStage, setHookStage } from './HookStage';
|
||||||
|
|
||||||
// hook对外入口
|
// hook对外入口
|
||||||
|
@ -27,7 +23,7 @@ export function runFunctionWithHooks<Props extends Record<string, any>, Arg>(
|
||||||
funcComp: (props: Props, arg: Arg) => any,
|
funcComp: (props: Props, arg: Arg) => any,
|
||||||
props: Props,
|
props: Props,
|
||||||
arg: Arg,
|
arg: Arg,
|
||||||
processing: VNode,
|
processing: VNode
|
||||||
) {
|
) {
|
||||||
// 重置全局变量
|
// 重置全局变量
|
||||||
resetGlobalVariable();
|
resetGlobalVariable();
|
||||||
|
@ -67,4 +63,3 @@ function resetGlobalVariable() {
|
||||||
setLastTimeHook(null);
|
setLastTimeHook(null);
|
||||||
setCurrentHook(null);
|
setCurrentHook(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,11 +13,7 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { createHook, getCurrentHook, throwNotInFuncError } from './BaseHook';
|
||||||
createHook,
|
|
||||||
getCurrentHook,
|
|
||||||
throwNotInFuncError
|
|
||||||
} from './BaseHook';
|
|
||||||
import { getHookStage, HookStage } from './HookStage';
|
import { getHookStage, HookStage } from './HookStage';
|
||||||
import { isArrayEqual } from '../utils/compare';
|
import { isArrayEqual } from '../utils/compare';
|
||||||
|
|
||||||
|
|
|
@ -13,12 +13,7 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { createHook, getCurrentHook, getLastTimeHook, throwNotInFuncError } from './BaseHook';
|
||||||
createHook,
|
|
||||||
getCurrentHook,
|
|
||||||
getLastTimeHook,
|
|
||||||
throwNotInFuncError
|
|
||||||
} from './BaseHook';
|
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { EffectConstant } from './EffectConstant';
|
import { EffectConstant } from './EffectConstant';
|
||||||
import type { Effect, EffectList } from './HookType';
|
import type { Effect, EffectList } from './HookType';
|
||||||
|
@ -26,7 +21,7 @@ import {getHookStage, HookStage} from './HookStage';
|
||||||
import { isArrayEqual } from '../utils/compare';
|
import { isArrayEqual } from '../utils/compare';
|
||||||
import { getProcessingVNode } from '../GlobalVar';
|
import { getProcessingVNode } from '../GlobalVar';
|
||||||
|
|
||||||
export function useEffectImpl(effectFunc: () => (() => void) | void, deps?: Array<any> | null,): void {
|
export function useEffectImpl(effectFunc: () => (() => void) | void, deps?: Array<any> | null): void {
|
||||||
// 异步触发的effect
|
// 异步触发的effect
|
||||||
useEffect(effectFunc, deps, EffectConstant.Effect);
|
useEffect(effectFunc, deps, EffectConstant.Effect);
|
||||||
}
|
}
|
||||||
|
@ -36,11 +31,7 @@ export function useLayoutEffectImpl(effectFunc: () => (() => void) | void, deps?
|
||||||
useEffect(effectFunc, deps, EffectConstant.LayoutEffect);
|
useEffect(effectFunc, deps, EffectConstant.LayoutEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useEffect(
|
function useEffect(effectFunc: () => (() => void) | void, deps: Array<any> | void | null, effectType: number): void {
|
||||||
effectFunc: () => (() => void) | void,
|
|
||||||
deps: Array<any> | void | null,
|
|
||||||
effectType: number
|
|
||||||
): void {
|
|
||||||
const stage = getHookStage();
|
const stage = getHookStage();
|
||||||
if (stage === null) {
|
if (stage === null) {
|
||||||
throwNotInFuncError();
|
throwNotInFuncError();
|
||||||
|
|
|
@ -21,7 +21,7 @@ import type {Ref} from './HookType';
|
||||||
export function useImperativeHandleImpl<R>(
|
export function useImperativeHandleImpl<R>(
|
||||||
ref: { current: R | null } | ((any) => any) | null | void,
|
ref: { current: R | null } | ((any) => any) | null | void,
|
||||||
func: () => R,
|
func: () => R,
|
||||||
dependencies?: Array<any> | null,
|
dependencies?: Array<any> | null
|
||||||
): void {
|
): void {
|
||||||
const stage = getHookStage();
|
const stage = getHookStage();
|
||||||
if (stage === null) {
|
if (stage === null) {
|
||||||
|
@ -36,10 +36,7 @@ function isNotNull(object: any): boolean {
|
||||||
return object !== null && object !== undefined;
|
return object !== null && object !== undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
function effectFunc<R>(
|
function effectFunc<R>(func: () => R, ref: Ref<R> | ((any) => any) | null): (() => void) | void {
|
||||||
func: () => R,
|
|
||||||
ref: Ref<R> | ((any) => any) | null,
|
|
||||||
): (() => void) | void {
|
|
||||||
if (typeof ref === 'function') {
|
if (typeof ref === 'function') {
|
||||||
const value = func();
|
const value = func();
|
||||||
ref(value);
|
ref(value);
|
||||||
|
|
|
@ -13,15 +13,11 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {
|
import { createHook, getCurrentHook, throwNotInFuncError } from './BaseHook';
|
||||||
createHook,
|
|
||||||
getCurrentHook,
|
|
||||||
throwNotInFuncError
|
|
||||||
} from './BaseHook';
|
|
||||||
import { getHookStage, HookStage } from './HookStage';
|
import { getHookStage, HookStage } from './HookStage';
|
||||||
import { isArrayEqual } from '../utils/compare';
|
import { isArrayEqual } from '../utils/compare';
|
||||||
|
|
||||||
export function useMemoImpl<V>(fun: () => V, deps?: Array<any> | null,): V {
|
export function useMemoImpl<V>(fun: () => V, deps?: Array<any> | null): V {
|
||||||
const stage = getHookStage();
|
const stage = getHookStage();
|
||||||
if (stage === null) {
|
if (stage === null) {
|
||||||
throwNotInFuncError();
|
throwNotInFuncError();
|
||||||
|
|
|
@ -137,7 +137,7 @@ function updateReducerHookState<S, A>(currentHookUpdates, currentHook, reducer):
|
||||||
|
|
||||||
// 计算stateValue值
|
// 计算stateValue值
|
||||||
function calculateNewState<S, A>(currentHookUpdates: Array<Update<S, A>>, currentHook, reducer: (S, A) => S) {
|
function calculateNewState<S, A>(currentHookUpdates: Array<Update<S, A>>, currentHook, reducer: (S, A) => S) {
|
||||||
let reducerObj = currentHook.state;
|
const reducerObj = currentHook.state;
|
||||||
let state = reducerObj.stateValue;
|
let state = reducerObj.stateValue;
|
||||||
|
|
||||||
// 循环遍历更新数组,计算新的状态值
|
// 循环遍历更新数组,计算新的状态值
|
||||||
|
|
|
@ -30,9 +30,7 @@ import {
|
||||||
} from './class/ClassLifeCycleProcessor';
|
} from './class/ClassLifeCycleProcessor';
|
||||||
import { FlagUtils, DidCapture } from '../vnode/VNodeFlags';
|
import { FlagUtils, DidCapture } from '../vnode/VNodeFlags';
|
||||||
import { markRef } from './BaseComponent';
|
import { markRef } from './BaseComponent';
|
||||||
import {
|
import { processUpdates } from '../UpdateHandler';
|
||||||
processUpdates,
|
|
||||||
} from '../UpdateHandler';
|
|
||||||
import { setProcessingClassVNode } from '../GlobalVar';
|
import { setProcessingClassVNode } from '../GlobalVar';
|
||||||
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
||||||
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||||
|
@ -41,9 +39,7 @@ const emptyContextObj = {};
|
||||||
// 获取当前节点的context
|
// 获取当前节点的context
|
||||||
export function getCurrentContext(clazz, processing: VNode) {
|
export function getCurrentContext(clazz, processing: VNode) {
|
||||||
const context = clazz.contextType;
|
const context = clazz.contextType;
|
||||||
return typeof context === 'object' && context !== null
|
return typeof context === 'object' && context !== null ? getNewContext(processing, context) : emptyContextObj;
|
||||||
? getNewContext(processing, context)
|
|
||||||
: emptyContextObj;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 挂载实例
|
// 挂载实例
|
||||||
|
@ -84,9 +80,7 @@ function createChildren(clazz: any, processing: VNode) {
|
||||||
const isCatchError = (processing.flags & DidCapture) === DidCapture;
|
const isCatchError = (processing.flags & DidCapture) === DidCapture;
|
||||||
|
|
||||||
// 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null
|
// 按照已有规格,如果捕获了错误却没有定义getDerivedStateFromError函数,返回的child为null
|
||||||
const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function'
|
const newElements = isCatchError && typeof clazz.getDerivedStateFromError !== 'function' ? null : inst.render();
|
||||||
? null
|
|
||||||
: inst.render();
|
|
||||||
|
|
||||||
processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated);
|
processing.child = createChildrenByDiff(processing, processing.child, newElements, !processing.isCreated);
|
||||||
return processing.child;
|
return processing.child;
|
||||||
|
@ -136,7 +130,8 @@ export function captureRender(processing: VNode): VNode | null {
|
||||||
// 挂载新组件,一定会更新
|
// 挂载新组件,一定会更新
|
||||||
mountInstance(ctor, processing, nextProps);
|
mountInstance(ctor, processing, nextProps);
|
||||||
shouldUpdate = true;
|
shouldUpdate = true;
|
||||||
} else { // 更新
|
} else {
|
||||||
|
// 更新
|
||||||
const newContext = getCurrentContext(ctor, processing);
|
const newContext = getCurrentContext(ctor, processing);
|
||||||
|
|
||||||
// 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props
|
// 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props
|
||||||
|
@ -150,9 +145,7 @@ export function captureRender(processing: VNode): VNode | null {
|
||||||
processUpdates(processing, inst, nextProps);
|
processUpdates(processing, inst, nextProps);
|
||||||
|
|
||||||
// 如果 props, state, context 都没有变化且 isForceUpdate 为 false则不需要更新
|
// 如果 props, state, context 都没有变化且 isForceUpdate 为 false则不需要更新
|
||||||
shouldUpdate = oldProps !== processing.props ||
|
shouldUpdate = oldProps !== processing.props || inst.state !== processing.state || processing.isForceUpdate;
|
||||||
inst.state !== processing.state ||
|
|
||||||
processing.isForceUpdate;
|
|
||||||
|
|
||||||
if (shouldUpdate) {
|
if (shouldUpdate) {
|
||||||
// derivedStateFromProps会修改nextState,因此需要调用
|
// derivedStateFromProps会修改nextState,因此需要调用
|
||||||
|
|
|
@ -36,4 +36,3 @@ export function captureRender(processing: VNode): VNode | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender() {}
|
export function bubbleRender() {}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,7 @@ import type { VNode, ContextType, ProviderType } from '../Types';
|
||||||
import { isSame } from '../utils/compare';
|
import { isSame } from '../utils/compare';
|
||||||
import { ClassComponent, ContextProvider } from '../vnode/VNodeTags';
|
import { ClassComponent, ContextProvider } from '../vnode/VNodeTags';
|
||||||
import { pushForceUpdate } from '../UpdateHandler';
|
import { pushForceUpdate } from '../UpdateHandler';
|
||||||
import {
|
import { resetContext, setContext } from '../ContextSaver';
|
||||||
resetContext,
|
|
||||||
setContext,
|
|
||||||
} from '../ContextSaver';
|
|
||||||
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
||||||
import { launchUpdateFromVNode } from '../TreeBuilder';
|
import { launchUpdateFromVNode } from '../TreeBuilder';
|
||||||
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
import { onlyUpdateChildVNodes } from '../vnode/VNodeCreator';
|
||||||
|
@ -62,15 +59,20 @@ function handleContextChange(processing: VNode, context: ContextType<any>): void
|
||||||
let isMatch = false;
|
let isMatch = false;
|
||||||
|
|
||||||
// 从vNode开始遍历
|
// 从vNode开始遍历
|
||||||
travelVNodeTree(vNode, node => {
|
travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
const depContexts = node.depContexts;
|
const depContexts = node.depContexts;
|
||||||
if (depContexts && depContexts.length) {
|
if (depContexts && depContexts.length) {
|
||||||
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
|
isMatch = matchDependencies(depContexts, context, node) ?? isMatch;
|
||||||
}
|
}
|
||||||
}, node =>
|
},
|
||||||
|
node =>
|
||||||
// 如果这是匹配的provider,则不要更深入地扫描
|
// 如果这是匹配的provider,则不要更深入地扫描
|
||||||
node.tag === ContextProvider && node.type === processing.type
|
node.tag === ContextProvider && node.type === processing.type,
|
||||||
, processing, null);
|
processing,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
// 找到了依赖context的子节点,触发一次更新
|
// 找到了依赖context的子节点,触发一次更新
|
||||||
if (isMatch) {
|
if (isMatch) {
|
||||||
|
@ -117,4 +119,3 @@ export function captureRender(processing: VNode): VNode | null {
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
resetContext(processing);
|
resetContext(processing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,28 +16,15 @@
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
import type { Props } from '../../dom/DOMOperator';
|
import type { Props } from '../../dom/DOMOperator';
|
||||||
|
|
||||||
import {
|
import { getNamespaceCtx, setNamespaceCtx, resetNamespaceCtx } from '../ContextSaver';
|
||||||
getNamespaceCtx,
|
import { appendChildElement, newDom, initDomProps, getPropChangeList, isTextChild } from '../../dom/DOMOperator';
|
||||||
setNamespaceCtx,
|
|
||||||
resetNamespaceCtx,
|
|
||||||
} from '../ContextSaver';
|
|
||||||
import {
|
|
||||||
appendChildElement,
|
|
||||||
newDom,
|
|
||||||
initDomProps, getPropChangeList,
|
|
||||||
isTextChild,
|
|
||||||
} from '../../dom/DOMOperator';
|
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { markRef } from './BaseComponent';
|
import { markRef } from './BaseComponent';
|
||||||
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
|
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
|
||||||
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
||||||
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||||
|
|
||||||
function updateDom(
|
function updateDom(processing: VNode, type: any, newProps: Props) {
|
||||||
processing: VNode,
|
|
||||||
type: any,
|
|
||||||
newProps: Props,
|
|
||||||
) {
|
|
||||||
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
// 如果oldProps !== newProps,意味着存在更新,并且需要处理其相关的副作用
|
||||||
const oldProps = processing.oldProps;
|
const oldProps = processing.oldProps;
|
||||||
if (oldProps === newProps) {
|
if (oldProps === newProps) {
|
||||||
|
@ -47,12 +34,7 @@ function updateDom(
|
||||||
|
|
||||||
const dom: Element = processing.realNode;
|
const dom: Element = processing.realNode;
|
||||||
|
|
||||||
const changeList = getPropChangeList(
|
const changeList = getPropChangeList(dom, type, oldProps, newProps);
|
||||||
dom,
|
|
||||||
type,
|
|
||||||
oldProps,
|
|
||||||
newProps,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 输入类型的直接标记更新
|
// 输入类型的直接标记更新
|
||||||
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
if (type === 'input' || type === 'textarea' || type === 'select' || type === 'option') {
|
||||||
|
@ -74,11 +56,7 @@ export function bubbleRender(processing: VNode) {
|
||||||
const newProps = processing.props;
|
const newProps = processing.props;
|
||||||
if (!processing.isCreated && processing.realNode != null) {
|
if (!processing.isCreated && processing.realNode != null) {
|
||||||
// 更新dom属性
|
// 更新dom属性
|
||||||
updateDom(
|
updateDom(processing, type, newProps);
|
||||||
processing,
|
|
||||||
type,
|
|
||||||
newProps,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (processing.oldRef !== processing.ref) {
|
if (processing.oldRef !== processing.ref) {
|
||||||
FlagUtils.markRef(processing);
|
FlagUtils.markRef(processing);
|
||||||
|
@ -87,25 +65,25 @@ export function bubbleRender(processing: VNode) {
|
||||||
const parentNamespace = getNamespaceCtx();
|
const parentNamespace = getNamespaceCtx();
|
||||||
|
|
||||||
// 创建dom
|
// 创建dom
|
||||||
const dom = newDom(
|
const dom = newDom(type, newProps, parentNamespace, processing);
|
||||||
type,
|
|
||||||
newProps,
|
|
||||||
parentNamespace,
|
|
||||||
processing,
|
|
||||||
);
|
|
||||||
|
|
||||||
// 把dom类型的子节点append到parent dom中
|
// 把dom类型的子节点append到parent dom中
|
||||||
const vNode = processing.child;
|
const vNode = processing.child;
|
||||||
if (vNode !== null) {
|
if (vNode !== null) {
|
||||||
// 向下递归它的子节点,查找所有终端节点。
|
// 向下递归它的子节点,查找所有终端节点。
|
||||||
travelVNodeTree(vNode, node => {
|
travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
appendChildElement(dom, node.realNode);
|
appendChildElement(dom, node.realNode);
|
||||||
}
|
}
|
||||||
}, node =>
|
},
|
||||||
|
node =>
|
||||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||||
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
|
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal,
|
||||||
, processing, null);
|
processing,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
processing.realNode = dom;
|
processing.realNode = dom;
|
||||||
|
|
|
@ -26,25 +26,24 @@ export function captureRender(): VNode | null {
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
const newText = processing.props;
|
const newText = processing.props;
|
||||||
|
|
||||||
if (!processing.isCreated && processing.realNode != null) { // 更新
|
if (!processing.isCreated && processing.realNode != null) {
|
||||||
|
// 更新
|
||||||
const oldText = processing.oldProps;
|
const oldText = processing.oldProps;
|
||||||
// 如果文本不同,将其标记为更新
|
// 如果文本不同,将其标记为更新
|
||||||
if (oldText !== newText) {
|
if (oldText !== newText) {
|
||||||
FlagUtils.markUpdate(processing);
|
FlagUtils.markUpdate(processing);
|
||||||
}
|
}
|
||||||
} else { // 初始化
|
} else {
|
||||||
|
// 初始化
|
||||||
if (typeof newText !== 'string') {
|
if (typeof newText !== 'string') {
|
||||||
// 如果存在bug,可能出现这种情况
|
// 如果存在bug,可能出现这种情况
|
||||||
throwIfTrue(
|
throwIfTrue(
|
||||||
processing.realNode === null,
|
processing.realNode === null,
|
||||||
'We must have new text for new mounted node. This error is likely ' +
|
'We must have new text for new mounted node. This error is likely ' +
|
||||||
'caused by a bug in Horizon. Please file an issue.',
|
'caused by a bug in Horizon. Please file an issue.'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
// 获得对应节点
|
// 获得对应节点
|
||||||
processing.realNode = newTextDom(
|
processing.realNode = newTextDom(newText, processing);
|
||||||
newText,
|
|
||||||
processing,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,4 +21,3 @@ export function captureRender(processing: VNode): VNode | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function bubbleRender() {}
|
export function bubbleRender() {}
|
||||||
|
|
||||||
|
|
|
@ -26,14 +26,11 @@ import { createChildrenByDiff } from '../diff/nodeDiffComparator';
|
||||||
// 在useState, useReducer的时候,会触发state变化
|
// 在useState, useReducer的时候,会触发state变化
|
||||||
let stateChange = false;
|
let stateChange = false;
|
||||||
|
|
||||||
export function bubbleRender() {
|
export function bubbleRender() {}
|
||||||
}
|
|
||||||
|
|
||||||
// 判断children是否可以复用
|
// 判断children是否可以复用
|
||||||
function checkIfCanReuseChildren(processing: VNode) {
|
function checkIfCanReuseChildren(processing: VNode) {
|
||||||
return !processing.isCreated &&
|
return !processing.isCreated && processing.oldProps === processing.props && !processing.isDepContextChange;
|
||||||
processing.oldProps === processing.props &&
|
|
||||||
!processing.isDepContextChange;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setStateChange(isUpdate) {
|
export function setStateChange(isUpdate) {
|
||||||
|
@ -44,11 +41,7 @@ export function isStateChange() {
|
||||||
return stateChange;
|
return stateChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function captureFunctionComponent(
|
export function captureFunctionComponent(processing: VNode, funcComp: any, nextProps: any) {
|
||||||
processing: VNode,
|
|
||||||
funcComp: any,
|
|
||||||
nextProps: any,
|
|
||||||
) {
|
|
||||||
// 函数组件内已完成异步动作
|
// 函数组件内已完成异步动作
|
||||||
if (processing.isSuspended) {
|
if (processing.isSuspended) {
|
||||||
// 由于首次被打断,应仍为首次渲染
|
// 由于首次被打断,应仍为首次渲染
|
||||||
|
@ -67,7 +60,7 @@ export function captureFunctionComponent(
|
||||||
processing.tag === ForwardRef ? funcComp.render : funcComp,
|
processing.tag === ForwardRef ? funcComp.render : funcComp,
|
||||||
nextProps,
|
nextProps,
|
||||||
processing.tag === ForwardRef ? processing.ref : undefined,
|
processing.tag === ForwardRef ? processing.ref : undefined,
|
||||||
processing,
|
processing
|
||||||
);
|
);
|
||||||
|
|
||||||
// 这里需要判断是否可以复用,因为函数组件比起其他组件,多了context、stateChange、或者store改变了 三个因素
|
// 这里需要判断是否可以复用,因为函数组件比起其他组件,多了context、stateChange、或者store改变了 三个因素
|
||||||
|
@ -86,15 +79,7 @@ export function captureFunctionComponent(
|
||||||
export function captureRender(processing: VNode): VNode | null {
|
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 = processing.isLazyComponent ? mergeDefaultProps(Component, unresolvedProps) : unresolvedProps;
|
||||||
processing.isLazyComponent
|
|
||||||
? mergeDefaultProps(Component, unresolvedProps)
|
|
||||||
: unresolvedProps;
|
|
||||||
|
|
||||||
return captureFunctionComponent(
|
return captureFunctionComponent(processing, Component, resolvedProps);
|
||||||
processing,
|
|
||||||
Component,
|
|
||||||
resolvedProps,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,12 +17,7 @@ import type { VNode } from '../Types';
|
||||||
|
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { getLazyVNodeTag } from '../vnode/VNodeCreator';
|
import { getLazyVNodeTag } from '../vnode/VNodeCreator';
|
||||||
import {
|
import { ClassComponent, ForwardRef, FunctionComponent, MemoComponent } from '../vnode/VNodeTags';
|
||||||
ClassComponent,
|
|
||||||
ForwardRef,
|
|
||||||
FunctionComponent,
|
|
||||||
MemoComponent,
|
|
||||||
} from '../vnode/VNodeTags';
|
|
||||||
import { throwIfTrue } from '../utils/throwIfTrue';
|
import { throwIfTrue } from '../utils/throwIfTrue';
|
||||||
import { captureFunctionComponent } from './FunctionComponent';
|
import { captureFunctionComponent } from './FunctionComponent';
|
||||||
import { captureRender as captureClassComponent } from './ClassComponent';
|
import { captureRender as captureClassComponent } from './ClassComponent';
|
||||||
|
@ -51,11 +46,7 @@ export function mergeDefaultProps(Component: any, props: object): object {
|
||||||
return props;
|
return props;
|
||||||
}
|
}
|
||||||
|
|
||||||
function captureLazyComponent(
|
function captureLazyComponent(processing, lazyComponent, shouldUpdate) {
|
||||||
processing,
|
|
||||||
lazyComponent,
|
|
||||||
shouldUpdate,
|
|
||||||
) {
|
|
||||||
if (!processing.isCreated) {
|
if (!processing.isCreated) {
|
||||||
// 每次加载lazy都当作mount来处理
|
// 每次加载lazy都当作mount来处理
|
||||||
processing.isCreated = true;
|
processing.isCreated = true;
|
||||||
|
@ -89,7 +80,7 @@ function captureLazyComponent(
|
||||||
'Element type is invalid. Received a promise that resolves to: %s. ' +
|
'Element type is invalid. Received a promise that resolves to: %s. ' +
|
||||||
'Lazy element type must resolve to a class or function.%s',
|
'Lazy element type must resolve to a class or function.%s',
|
||||||
Component,
|
Component,
|
||||||
'',
|
''
|
||||||
);
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,12 +17,7 @@ import type { VNode, PromiseType } from '../Types';
|
||||||
|
|
||||||
import { FlagUtils, Interrupted } from '../vnode/VNodeFlags';
|
import { FlagUtils, Interrupted } from '../vnode/VNodeFlags';
|
||||||
import { onlyUpdateChildVNodes, updateVNode, createFragmentVNode } from '../vnode/VNodeCreator';
|
import { onlyUpdateChildVNodes, updateVNode, createFragmentVNode } from '../vnode/VNodeCreator';
|
||||||
import {
|
import { ClassComponent, ForwardRef, FunctionComponent, SuspenseComponent } from '../vnode/VNodeTags';
|
||||||
ClassComponent,
|
|
||||||
ForwardRef,
|
|
||||||
FunctionComponent,
|
|
||||||
SuspenseComponent,
|
|
||||||
} from '../vnode/VNodeTags';
|
|
||||||
import { pushForceUpdate } from '../UpdateHandler';
|
import { pushForceUpdate } from '../UpdateHandler';
|
||||||
import { launchUpdateFromVNode, tryRenderFromRoot } from '../TreeBuilder';
|
import { launchUpdateFromVNode, tryRenderFromRoot } from '../TreeBuilder';
|
||||||
import { updateShouldUpdateOfTree } from '../vnode/VNodeShouldUpdate';
|
import { updateShouldUpdateOfTree } from '../vnode/VNodeShouldUpdate';
|
||||||
|
@ -141,11 +136,7 @@ function updateFallback(processing: VNode): Array<VNode> | VNode | null {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null {
|
export function captureRender(processing: VNode, shouldUpdate: boolean): Array<VNode> | VNode | null {
|
||||||
if (
|
if (!processing.isCreated && processing.oldProps === processing.props && !shouldUpdate) {
|
||||||
!processing.isCreated &&
|
|
||||||
processing.oldProps === processing.props &&
|
|
||||||
!shouldUpdate
|
|
||||||
) {
|
|
||||||
if (processing.suspenseState.childStatus === SuspenseChildStatus.ShowFallback) {
|
if (processing.suspenseState.childStatus === SuspenseChildStatus.ShowFallback) {
|
||||||
// 当显示fallback时,suspense的子组件要更新
|
// 当显示fallback时,suspense的子组件要更新
|
||||||
return updateFallback(processing);
|
return updateFallback(processing);
|
||||||
|
@ -158,8 +149,9 @@ export function captureRender(processing: VNode, shouldUpdate: boolean): Array<V
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
const { childStatus, oldChildStatus } = processing.suspenseState;
|
const { childStatus, oldChildStatus } = processing.suspenseState;
|
||||||
if (childStatus === SuspenseChildStatus.ShowFallback
|
if (
|
||||||
|| (!processing.isCreated && oldChildStatus === SuspenseChildStatus.ShowFallback)
|
childStatus === SuspenseChildStatus.ShowFallback ||
|
||||||
|
(!processing.isCreated && oldChildStatus === SuspenseChildStatus.ShowFallback)
|
||||||
) {
|
) {
|
||||||
FlagUtils.markUpdate(processing);
|
FlagUtils.markUpdate(processing);
|
||||||
}
|
}
|
||||||
|
@ -183,7 +175,6 @@ export function handleSuspenseChildThrowError(parent: VNode, processing: VNode,
|
||||||
}
|
}
|
||||||
vNode.suspenseState.promiseSet.add(promise);
|
vNode.suspenseState.promiseSet.add(promise);
|
||||||
|
|
||||||
|
|
||||||
// 移除生命周期flag 和 中断flag
|
// 移除生命周期flag 和 中断flag
|
||||||
FlagUtils.removeLifecycleEffectFlags(processing);
|
FlagUtils.removeLifecycleEffectFlags(processing);
|
||||||
FlagUtils.removeFlag(processing, Interrupted);
|
FlagUtils.removeFlag(processing, Interrupted);
|
||||||
|
|
|
@ -32,7 +32,7 @@ function updateTreeRoot(processing) {
|
||||||
processing.isCreated || updates === null,
|
processing.isCreated || updates === null,
|
||||||
'If the root does not have an updates, we should have already ' +
|
'If the root does not have an updates, we should have already ' +
|
||||||
'bailed out. This error is likely caused by a bug. Please ' +
|
'bailed out. This error is likely caused by a bug. Please ' +
|
||||||
'file an issue.',
|
'file an issue.'
|
||||||
);
|
);
|
||||||
|
|
||||||
const newProps = processing.props;
|
const newProps = processing.props;
|
||||||
|
|
|
@ -17,12 +17,7 @@ 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, newUpdate, UpdateState, processUpdates } from '../../UpdateHandler';
|
||||||
pushUpdate,
|
|
||||||
newUpdate,
|
|
||||||
UpdateState,
|
|
||||||
processUpdates,
|
|
||||||
} from '../../UpdateHandler';
|
|
||||||
import { launchUpdateFromVNode } from '../../TreeBuilder';
|
import { launchUpdateFromVNode } from '../../TreeBuilder';
|
||||||
import { FlagUtils } from '../../vnode/VNodeFlags';
|
import { FlagUtils } from '../../vnode/VNodeFlags';
|
||||||
import { getCurrentContext } from '../ClassComponent';
|
import { getCurrentContext } from '../ClassComponent';
|
||||||
|
@ -31,7 +26,7 @@ import { PureComponent } from '../../components/BaseClassComponent';
|
||||||
export function callDerivedStateFromProps(
|
export function callDerivedStateFromProps(
|
||||||
processing: VNode,
|
processing: VNode,
|
||||||
getDerivedStateFromProps: (props: object, state: object) => object,
|
getDerivedStateFromProps: (props: object, state: object) => object,
|
||||||
nextProps: object,
|
nextProps: object
|
||||||
) {
|
) {
|
||||||
if (getDerivedStateFromProps) {
|
if (getDerivedStateFromProps) {
|
||||||
const oldState = processing.state;
|
const oldState = processing.state;
|
||||||
|
@ -40,9 +35,7 @@ export function callDerivedStateFromProps(
|
||||||
const newState = getDerivedStateFromProps(nextProps, oldState);
|
const newState = getDerivedStateFromProps(nextProps, oldState);
|
||||||
|
|
||||||
// 组件未返回state,需要返回旧的preState
|
// 组件未返回state,需要返回旧的preState
|
||||||
processing.state = newState === null || newState === undefined
|
processing.state = newState === null || newState === undefined ? oldState : { ...oldState, ...newState };
|
||||||
? oldState
|
|
||||||
: { ...oldState, ...newState };
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,7 +61,7 @@ export function callShouldComponentUpdate(
|
||||||
oldProps: object,
|
oldProps: object,
|
||||||
newProps: object,
|
newProps: object,
|
||||||
newState: object,
|
newState: object,
|
||||||
newContext: object,
|
newContext: object
|
||||||
) {
|
) {
|
||||||
const inst = processing.realNode;
|
const inst = processing.realNode;
|
||||||
|
|
||||||
|
@ -169,4 +162,3 @@ export function markComponentDidUpdate(processing: VNode) {
|
||||||
FlagUtils.markUpdate(processing);
|
FlagUtils.markUpdate(processing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,9 +44,7 @@ import {
|
||||||
SuspenseComponent,
|
SuspenseComponent,
|
||||||
} from '../vnode/VNodeTags';
|
} from '../vnode/VNodeTags';
|
||||||
|
|
||||||
export {
|
export { BaseComponentRender };
|
||||||
BaseComponentRender,
|
|
||||||
};
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
[ClassComponent]: ClassComponentRender,
|
[ClassComponent]: ClassComponentRender,
|
||||||
|
|
|
@ -18,20 +18,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
import type {
|
import type { Effect as HookEffect, EffectList } from '../hooks/HookType';
|
||||||
Effect as HookEffect,
|
|
||||||
EffectList,
|
|
||||||
} from '../hooks/HookType';
|
|
||||||
import { runAsync } from '../taskExecutor/TaskExecutor';
|
import { runAsync } from '../taskExecutor/TaskExecutor';
|
||||||
import {
|
import { copyExecuteMode, InRender, setExecuteMode, changeMode } from '../ExecuteMode';
|
||||||
copyExecuteMode, InRender, setExecuteMode,changeMode
|
|
||||||
} from '../ExecuteMode';
|
|
||||||
import { EffectConstant } from '../hooks/EffectConstant';
|
import { EffectConstant } from '../hooks/EffectConstant';
|
||||||
|
|
||||||
let hookEffects: Array<HookEffect | VNode> = [];
|
let hookEffects: Array<HookEffect | VNode> = [];
|
||||||
let hookRemoveEffects: Array<HookEffect | VNode> = [];
|
let hookRemoveEffects: Array<HookEffect | VNode> = [];
|
||||||
// 是否正在异步调度effects
|
// 是否正在异步调度effects
|
||||||
let isScheduling: boolean = false;
|
let isScheduling = false;
|
||||||
|
|
||||||
export function setSchedulingEffects(value) {
|
export function setSchedulingEffects(value) {
|
||||||
isScheduling = value;
|
isScheduling = value;
|
||||||
|
@ -69,7 +64,7 @@ export function runAsyncEffects() {
|
||||||
// 调用effect destroy
|
// 调用effect destroy
|
||||||
const removeEffects = hookRemoveEffects;
|
const removeEffects = hookRemoveEffects;
|
||||||
hookRemoveEffects = [];
|
hookRemoveEffects = [];
|
||||||
removeEffects.forEach((effect) => {
|
removeEffects.forEach(effect => {
|
||||||
const destroy = effect.removeEffect;
|
const destroy = effect.removeEffect;
|
||||||
effect.removeEffect = undefined;
|
effect.removeEffect = undefined;
|
||||||
|
|
||||||
|
@ -85,7 +80,7 @@ export function runAsyncEffects() {
|
||||||
// 调用effect create
|
// 调用effect create
|
||||||
const createEffects = hookEffects;
|
const createEffects = hookEffects;
|
||||||
hookEffects = [];
|
hookEffects = [];
|
||||||
createEffects.forEach((effect) => {
|
createEffects.forEach(effect => {
|
||||||
try {
|
try {
|
||||||
const create = effect.effect;
|
const create = effect.effect;
|
||||||
|
|
||||||
|
@ -106,14 +101,16 @@ export function callEffectRemove(vNode: VNode) {
|
||||||
const { removeEffect, effectConstant } = effect;
|
const { removeEffect, effectConstant } = effect;
|
||||||
|
|
||||||
if (removeEffect !== undefined) {
|
if (removeEffect !== undefined) {
|
||||||
if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) { // 如果是useEffect,就异步调用
|
if ((effectConstant & EffectConstant.Effect) !== EffectConstant.NoEffect) {
|
||||||
|
// 如果是useEffect,就异步调用
|
||||||
hookRemoveEffects.push(effect);
|
hookRemoveEffects.push(effect);
|
||||||
|
|
||||||
if (!isScheduling) {
|
if (!isScheduling) {
|
||||||
isScheduling = true;
|
isScheduling = true;
|
||||||
runAsync(runAsyncEffects);
|
runAsync(runAsyncEffects);
|
||||||
}
|
}
|
||||||
} else { // 是useLayoutEffect,直接执行
|
} else {
|
||||||
|
// 是useLayoutEffect,直接执行
|
||||||
removeEffect();
|
removeEffect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,12 +50,7 @@ import {
|
||||||
callUseLayoutEffectRemove,
|
callUseLayoutEffectRemove,
|
||||||
} from './HookEffectHandler';
|
} from './HookEffectHandler';
|
||||||
import { handleSubmitError } from '../ErrorHandler';
|
import { handleSubmitError } from '../ErrorHandler';
|
||||||
import {
|
import { travelVNodeTree, clearVNode, isDomVNode, getSiblingDom } from '../vnode/VNodeUtils';
|
||||||
travelVNodeTree,
|
|
||||||
clearVNode,
|
|
||||||
isDomVNode,
|
|
||||||
getSiblingDom,
|
|
||||||
} from '../vnode/VNodeUtils';
|
|
||||||
import { shouldAutoFocus } from '../../dom/utils/Common';
|
import { shouldAutoFocus } from '../../dom/utils/Common';
|
||||||
|
|
||||||
function callComponentWillUnmount(vNode: VNode, instance: any) {
|
function callComponentWillUnmount(vNode: VNode, instance: any) {
|
||||||
|
@ -67,13 +62,10 @@ function callComponentWillUnmount(vNode: VNode, instance: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用界面变化前的生命周期
|
// 调用界面变化前的生命周期
|
||||||
function callBeforeSubmitLifeCycles(
|
function callBeforeSubmitLifeCycles(vNode: VNode): void {
|
||||||
vNode: VNode,
|
if (vNode.tag === ClassComponent && !vNode.isCreated) {
|
||||||
): void {
|
// 调用instance.getSnapshotBeforeUpdate
|
||||||
if (vNode.tag === ClassComponent && !vNode.isCreated) { // 调用instance.getSnapshotBeforeUpdate
|
const prevProps = vNode.isLazyComponent ? mergeDefaultProps(vNode.type, vNode.oldProps) : vNode.oldProps;
|
||||||
const prevProps = vNode.isLazyComponent
|
|
||||||
? mergeDefaultProps(vNode.type, vNode.oldProps)
|
|
||||||
: vNode.oldProps;
|
|
||||||
const prevState = vNode.oldState;
|
const prevState = vNode.oldState;
|
||||||
const instance = vNode.realNode;
|
const instance = vNode.realNode;
|
||||||
|
|
||||||
|
@ -98,9 +90,7 @@ function callStateCallback(vNode: VNode, obj: any): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用界面变化后的生命周期
|
// 调用界面变化后的生命周期
|
||||||
function callAfterSubmitLifeCycles(
|
function callAfterSubmitLifeCycles(vNode: VNode): void {
|
||||||
vNode: VNode,
|
|
||||||
): void {
|
|
||||||
switch (vNode.tag) {
|
switch (vNode.tag) {
|
||||||
case FunctionComponent:
|
case FunctionComponent:
|
||||||
case ForwardRef: {
|
case ForwardRef: {
|
||||||
|
@ -116,17 +106,10 @@ function callAfterSubmitLifeCycles(
|
||||||
if (vNode.isCreated) {
|
if (vNode.isCreated) {
|
||||||
instance.componentDidMount();
|
instance.componentDidMount();
|
||||||
} else {
|
} else {
|
||||||
const prevProps =
|
const prevProps = vNode.isLazyComponent ? mergeDefaultProps(vNode.type, vNode.oldProps) : vNode.oldProps;
|
||||||
vNode.isLazyComponent
|
|
||||||
? mergeDefaultProps(vNode.type, vNode.oldProps)
|
|
||||||
: vNode.oldProps;
|
|
||||||
const prevState = vNode.oldState;
|
const prevState = vNode.oldState;
|
||||||
|
|
||||||
instance.componentDidUpdate(
|
instance.componentDidUpdate(prevProps, prevState, instance.__snapshotResult);
|
||||||
prevProps,
|
|
||||||
prevState,
|
|
||||||
instance.__snapshotResult,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,7 +135,9 @@ function callAfterSubmitLifeCycles(
|
||||||
}
|
}
|
||||||
|
|
||||||
function hideOrUnhideAllChildren(vNode, isHidden) {
|
function hideOrUnhideAllChildren(vNode, isHidden) {
|
||||||
travelVNodeTree(vNode, (node: VNode) => {
|
travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
(node: VNode) => {
|
||||||
const instance = node.realNode;
|
const instance = node.realNode;
|
||||||
|
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
|
@ -162,7 +147,11 @@ function hideOrUnhideAllChildren(vNode, isHidden) {
|
||||||
unHideDom(node.tag, instance, node.props);
|
unHideDom(node.tag, instance, node.props);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, null, vNode, null);
|
},
|
||||||
|
null,
|
||||||
|
vNode,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function attachRef(vNode: VNode) {
|
function attachRef(vNode: VNode) {
|
||||||
|
@ -172,7 +161,7 @@ function attachRef(vNode: VNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function detachRef(vNode: VNode, isOldRef?: boolean) {
|
function detachRef(vNode: VNode, isOldRef?: boolean) {
|
||||||
let ref = (isOldRef ? vNode.oldRef : vNode.ref);
|
const ref = isOldRef ? vNode.oldRef : vNode.ref;
|
||||||
|
|
||||||
handleRef(vNode, ref, null);
|
handleRef(vNode, ref, null);
|
||||||
}
|
}
|
||||||
|
@ -233,12 +222,17 @@ function unmountVNode(vNode: VNode): void {
|
||||||
|
|
||||||
// 卸载vNode,递归遍历子vNode
|
// 卸载vNode,递归遍历子vNode
|
||||||
function unmountNestedVNodes(vNode: VNode): void {
|
function unmountNestedVNodes(vNode: VNode): void {
|
||||||
travelVNodeTree(vNode, (node) => {
|
travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
unmountVNode(node);
|
unmountVNode(node);
|
||||||
}, node =>
|
},
|
||||||
|
node =>
|
||||||
// 如果是DomPortal,不需要遍历child
|
// 如果是DomPortal,不需要遍历child
|
||||||
node.tag === DomPortal
|
node.tag === DomPortal,
|
||||||
, vNode, null);
|
vNode,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitAddition(vNode: VNode): void {
|
function submitAddition(vNode: VNode): void {
|
||||||
|
@ -269,11 +263,7 @@ function submitAddition(vNode: VNode): void {
|
||||||
insertOrAppendPlacementNode(vNode, before, parentDom);
|
insertOrAppendPlacementNode(vNode, before, parentDom);
|
||||||
}
|
}
|
||||||
|
|
||||||
function insertOrAppendPlacementNode(
|
function insertOrAppendPlacementNode(node: VNode, beforeDom: Element | null, parent: Element | Container): void {
|
||||||
node: VNode,
|
|
||||||
beforeDom: Element | null,
|
|
||||||
parent: Element | Container,
|
|
||||||
): void {
|
|
||||||
const { tag, realNode } = node;
|
const { tag, realNode } = node;
|
||||||
|
|
||||||
if (isDomVNode(node)) {
|
if (isDomVNode(node)) {
|
||||||
|
@ -305,7 +295,9 @@ function unmountDomComponents(vNode: VNode): void {
|
||||||
// 这两个变量要一起更新
|
// 这两个变量要一起更新
|
||||||
let currentParent;
|
let currentParent;
|
||||||
|
|
||||||
travelVNodeTree(vNode, (node) => {
|
travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
if (!currentParentIsValid) {
|
if (!currentParentIsValid) {
|
||||||
let parent = node.parent;
|
let parent = node.parent;
|
||||||
let tag;
|
let tag;
|
||||||
|
@ -333,14 +325,18 @@ function unmountDomComponents(vNode: VNode): void {
|
||||||
} else {
|
} else {
|
||||||
unmountVNode(node);
|
unmountVNode(node);
|
||||||
}
|
}
|
||||||
}, node =>
|
},
|
||||||
|
node =>
|
||||||
// 如果是dom不用再遍历child
|
// 如果是dom不用再遍历child
|
||||||
node.tag === DomComponent || node.tag === DomText, vNode, (node) => {
|
node.tag === DomComponent || node.tag === DomText,
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
if (node.tag === DomPortal) {
|
if (node.tag === DomPortal) {
|
||||||
// 当离开portal,需要重新设置parent
|
// 当离开portal,需要重新设置parent
|
||||||
currentParentIsValid = false;
|
currentParentIsValid = false;
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function submitClear(vNode: VNode): void {
|
function submitClear(vNode: VNode): void {
|
||||||
|
|
|
@ -21,27 +21,24 @@ import {handleSubmitError} from '../ErrorHandler';
|
||||||
import {
|
import {
|
||||||
attachRef,
|
attachRef,
|
||||||
callAfterSubmitLifeCycles,
|
callAfterSubmitLifeCycles,
|
||||||
callBeforeSubmitLifeCycles, submitDeletion, submitAddition,
|
callBeforeSubmitLifeCycles,
|
||||||
submitResetTextContent, submitUpdate, detachRef, submitClear,
|
submitDeletion,
|
||||||
|
submitAddition,
|
||||||
|
submitResetTextContent,
|
||||||
|
submitUpdate,
|
||||||
|
detachRef,
|
||||||
|
submitClear,
|
||||||
} from './LifeCycleHandler';
|
} from './LifeCycleHandler';
|
||||||
import { tryRenderFromRoot } from '../TreeBuilder';
|
import { tryRenderFromRoot } from '../TreeBuilder';
|
||||||
import {
|
import { InRender, copyExecuteMode, setExecuteMode, changeMode } from '../ExecuteMode';
|
||||||
InRender,
|
import { isSchedulingEffects, setSchedulingEffects } from './HookEffectHandler';
|
||||||
copyExecuteMode,
|
|
||||||
setExecuteMode,
|
|
||||||
changeMode,
|
|
||||||
} from '../ExecuteMode';
|
|
||||||
import {
|
|
||||||
isSchedulingEffects,
|
|
||||||
setSchedulingEffects,
|
|
||||||
} from './HookEffectHandler';
|
|
||||||
import { getStartVNode } from '../GlobalVar';
|
import { getStartVNode } from '../GlobalVar';
|
||||||
|
|
||||||
let rootThrowError = null;
|
let rootThrowError = null;
|
||||||
|
|
||||||
// 防止死循环调用update
|
// 防止死循环调用update
|
||||||
const LOOPING_UPDATE_LIMIT = 50;
|
const LOOPING_UPDATE_LIMIT = 50;
|
||||||
let loopingUpdateCount: number = 0;
|
let loopingUpdateCount = 0;
|
||||||
let lastRoot: VNode | null = null;
|
let lastRoot: VNode | null = null;
|
||||||
|
|
||||||
export function submitToRender(treeRoot) {
|
export function submitToRender(treeRoot) {
|
||||||
|
|
|
@ -21,7 +21,6 @@ let isMessageLoopRunning = false;
|
||||||
let browserCallback = null;
|
let browserCallback = null;
|
||||||
const { port1, port2 } = new MessageChannel();
|
const { port1, port2 } = new MessageChannel();
|
||||||
|
|
||||||
|
|
||||||
export function isOverTime() {
|
export function isOverTime() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +35,8 @@ const callRenderTasks = () => {
|
||||||
// 执行callback
|
// 执行callback
|
||||||
const hasMoreTask = browserCallback();
|
const hasMoreTask = browserCallback();
|
||||||
|
|
||||||
if (!hasMoreTask) { // 没有更多task
|
if (!hasMoreTask) {
|
||||||
|
// 没有更多task
|
||||||
isMessageLoopRunning = false;
|
isMessageLoopRunning = false;
|
||||||
browserCallback = null;
|
browserCallback = null;
|
||||||
} else {
|
} else {
|
||||||
|
@ -49,7 +49,6 @@ const callRenderTasks = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
port1.onmessage = callRenderTasks;
|
port1.onmessage = callRenderTasks;
|
||||||
|
|
||||||
export function requestBrowserCallback(callback) {
|
export function requestBrowserCallback(callback) {
|
||||||
|
|
|
@ -45,7 +45,7 @@ function callRenderQueue() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let callback;
|
let callback;
|
||||||
while (callback = renderQueue.shift()) {
|
while ((callback = renderQueue.shift())) {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,10 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { Node } from '../taskExecutor/TaskQueue';
|
import { Node } from '../taskExecutor/TaskQueue';
|
||||||
import {
|
import { requestBrowserCallback, isOverTime } from './BrowserAsync';
|
||||||
requestBrowserCallback,
|
|
||||||
isOverTime,
|
|
||||||
} from './BrowserAsync';
|
|
||||||
|
|
||||||
import { add, shift, first, remove } from './TaskQueue';
|
import { add, shift, first, remove } from './TaskQueue';
|
||||||
|
|
||||||
|
@ -60,7 +57,8 @@ function callTasks() {
|
||||||
|
|
||||||
if (task === first()) {
|
if (task === first()) {
|
||||||
shift();
|
shift();
|
||||||
} else { // 执行任务中可能插入了新任务
|
} else {
|
||||||
|
// 执行任务中可能插入了新任务
|
||||||
remove(task);
|
remove(task);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -109,9 +107,4 @@ function cancelTask(task) {
|
||||||
task.callback = null;
|
task.callback = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export { ImmediatePriority, NormalPriority, runAsync, cancelTask };
|
||||||
ImmediatePriority,
|
|
||||||
NormalPriority,
|
|
||||||
runAsync,
|
|
||||||
cancelTask,
|
|
||||||
};
|
|
||||||
|
|
|
@ -57,8 +57,8 @@ export function shallowCompare(paramX: any, paramY: any): boolean {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return keysX.every((key, i) =>
|
return keysX.every(
|
||||||
Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]])
|
(key, i) => Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]])
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,6 @@
|
||||||
|
|
||||||
import type { VNode } from './VNode';
|
import type { VNode } from './VNode';
|
||||||
|
|
||||||
|
|
||||||
export const InitFlag = /** */ 0;
|
export const InitFlag = /** */ 0;
|
||||||
// vNode节点的flags
|
// vNode节点的flags
|
||||||
export const DirectAddition = /** */ 1 << 0; // 在本次更新前入股父dom没有子节点,说明本次可以直接添加至父节点,不需要通过 getSiblingDom 找到 before 节点
|
export const DirectAddition = /** */ 1 << 0; // 在本次更新前入股父dom没有子节点,说明本次可以直接添加至父节点,不需要通过 getSiblingDom 找到 before 节点
|
||||||
|
@ -44,7 +43,8 @@ export class FlagUtils {
|
||||||
static removeLifecycleEffectFlags(node) {
|
static removeLifecycleEffectFlags(node) {
|
||||||
node.flags &= ~LifecycleEffectArr;
|
node.flags &= ~LifecycleEffectArr;
|
||||||
}
|
}
|
||||||
static hasAnyFlag(node: VNode) { // 有标志位
|
static hasAnyFlag(node: VNode) {
|
||||||
|
// 有标志位
|
||||||
return node.flags !== InitFlag;
|
return node.flags !== InitFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,4 +97,3 @@ export class FlagUtils {
|
||||||
node.flags |= Clear;
|
node.flags |= Clear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,7 +70,8 @@ export function updateParentsChildShouldUpdate(vNode: VNode) {
|
||||||
let node = vNode.parent;
|
let node = vNode.parent;
|
||||||
const isShouldUpdate = vNode.shouldUpdate || vNode.childShouldUpdate;
|
const isShouldUpdate = vNode.shouldUpdate || vNode.childShouldUpdate;
|
||||||
|
|
||||||
if (isShouldUpdate) { // 开始节点是shouldUpdate或childShouldUpdate
|
if (isShouldUpdate) {
|
||||||
|
// 开始节点是shouldUpdate或childShouldUpdate
|
||||||
// 更新从当前节点到根节点的childShouldUpdate为true
|
// 更新从当前节点到根节点的childShouldUpdate为true
|
||||||
setParentsChildShouldUpdate(node);
|
setParentsChildShouldUpdate(node);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -125,20 +125,22 @@ export function isDomVNode(node: VNode) {
|
||||||
|
|
||||||
// 是容器类型的vNode
|
// 是容器类型的vNode
|
||||||
function isDomContainer(vNode: VNode): boolean {
|
function isDomContainer(vNode: VNode): boolean {
|
||||||
return (
|
return vNode.tag === DomComponent || vNode.tag === TreeRoot || vNode.tag === DomPortal;
|
||||||
vNode.tag === DomComponent ||
|
|
||||||
vNode.tag === TreeRoot ||
|
|
||||||
vNode.tag === DomPortal
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findDomVNode(vNode: VNode): VNode | null {
|
export function findDomVNode(vNode: VNode): VNode | null {
|
||||||
return travelVNodeTree(vNode, (node) => {
|
return travelVNodeTree(
|
||||||
|
vNode,
|
||||||
|
node => {
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, null, vNode, null);
|
},
|
||||||
|
null,
|
||||||
|
vNode,
|
||||||
|
null
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findDOMByClassInst(inst) {
|
export function findDOMByClassInst(inst) {
|
||||||
|
|
|
@ -4,7 +4,8 @@
|
||||||
"libs/*"
|
"libs/*"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint . --ext .ts",
|
"lint": "eslint . --ext .ts --fix",
|
||||||
|
"prettier": "prettier -w libs/**/*.ts",
|
||||||
"build": "rollup --config ./scripts/rollup/rollup.config.js",
|
"build": "rollup --config ./scripts/rollup/rollup.config.js",
|
||||||
"build:watch": "rollup --watch --config ./scripts/rollup/rollup.config.js",
|
"build:watch": "rollup --watch --config ./scripts/rollup/rollup.config.js",
|
||||||
"build:3rdLib": "node ./scripts/gen3rdLib.js build:3rdLib",
|
"build:3rdLib": "node ./scripts/gen3rdLib.js build:3rdLib",
|
||||||
|
|
Loading…
Reference in New Issue