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