Match-id-2cd3434dfcebed0f77a3028ccc5bca82c3fd9326
This commit is contained in:
commit
305ab79bc5
|
@ -14,13 +14,9 @@ import {
|
||||||
TreeRoot,
|
TreeRoot,
|
||||||
} from '../renderer/vnode/VNodeTags';
|
} from '../renderer/vnode/VNodeTags';
|
||||||
|
|
||||||
const prefix = '_horizon';
|
const INTERNAL_VNODE = '_horizon_VNode';
|
||||||
|
const INTERNAL_PROPS = '_horizon_Props';
|
||||||
const internalKeys = {
|
const INTERNAL_NONDELEGATEEVENTS = '_horizon_NonDelegatedEvents';
|
||||||
VNode: `${prefix}VNode`,
|
|
||||||
props: `${prefix}Props`,
|
|
||||||
nonDelegatedEvents: `${prefix}NonDelegatedEvents`,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 通过 VNode 实例获取 DOM 节点
|
// 通过 VNode 实例获取 DOM 节点
|
||||||
export function getDom(vNode: VNode): Element | Text | null {
|
export function getDom(vNode: VNode): Element | Text | null {
|
||||||
|
@ -36,12 +32,12 @@ export function saveVNode(
|
||||||
vNode: VNode,
|
vNode: VNode,
|
||||||
dom: Element | Text | Container,
|
dom: Element | Text | Container,
|
||||||
): void {
|
): void {
|
||||||
dom[internalKeys.VNode] = vNode;
|
dom[INTERNAL_VNODE] = vNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 用 DOM 节点,来找其对应的 VNode 实例
|
// 用 DOM 节点,来找其对应的 VNode 实例
|
||||||
export function getVNode(dom: Node|Container): VNode | null {
|
export function getVNode(dom: Node|Container): VNode | null {
|
||||||
const vNode = dom[internalKeys.VNode] || (dom as Container)._treeRoot;
|
const vNode = dom[INTERNAL_VNODE] || (dom as Container)._treeRoot;
|
||||||
if (vNode) {
|
if (vNode) {
|
||||||
const {tag} = vNode;
|
const {tag} = vNode;
|
||||||
if (tag === DomComponent || tag === DomText || tag === TreeRoot) {
|
if (tag === DomComponent || tag === DomText || tag === TreeRoot) {
|
||||||
|
@ -53,7 +49,7 @@ export function getVNode(dom: Node|Container): VNode | null {
|
||||||
|
|
||||||
// 用 DOM 对象,来寻找其对应或者说是最近父级的 vNode
|
// 用 DOM 对象,来寻找其对应或者说是最近父级的 vNode
|
||||||
export function getNearestVNode(dom: Node): null | VNode {
|
export function getNearestVNode(dom: Node): null | VNode {
|
||||||
let vNode = dom[internalKeys.VNode];
|
let vNode = dom[INTERNAL_VNODE];
|
||||||
if (vNode) { // 如果是已经被框架标记过的 DOM 节点,那么直接返回其 VNode 实例
|
if (vNode) { // 如果是已经被框架标记过的 DOM 节点,那么直接返回其 VNode 实例
|
||||||
return vNode;
|
return vNode;
|
||||||
}
|
}
|
||||||
|
@ -62,7 +58,7 @@ export function getNearestVNode(dom: Node): null | VNode {
|
||||||
let parentDom = dom.parentNode;
|
let parentDom = dom.parentNode;
|
||||||
let nearVNode = null;
|
let nearVNode = null;
|
||||||
while (parentDom) {
|
while (parentDom) {
|
||||||
vNode = parentDom[internalKeys.VNode];
|
vNode = parentDom[INTERNAL_VNODE];
|
||||||
if (vNode) {
|
if (vNode) {
|
||||||
nearVNode = vNode;
|
nearVNode = vNode;
|
||||||
break;
|
break;
|
||||||
|
@ -74,19 +70,19 @@ export function getNearestVNode(dom: Node): null | VNode {
|
||||||
|
|
||||||
// 获取 vNode 上的属性相关信息
|
// 获取 vNode 上的属性相关信息
|
||||||
export function getVNodeProps(dom: Element | Text): Props | null{
|
export function getVNodeProps(dom: Element | Text): Props | null{
|
||||||
return dom[internalKeys.props] || null;
|
return dom[INTERNAL_PROPS] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 DOM 属性相关信息挂到 DOM 对象的特定属性上
|
// 将 DOM 属性相关信息挂到 DOM 对象的特定属性上
|
||||||
export function updateVNodeProps(dom: Element | Text, props: Props): void {
|
export function updateVNodeProps(dom: Element | Text, props: Props): void {
|
||||||
dom[internalKeys.props] = props;
|
dom[INTERNAL_PROPS] = props;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getNonDelegatedListenerMap(dom: Element | Text): Map<string, EventListener> {
|
export function getNonDelegatedListenerMap(dom: Element | Text): Map<string, EventListener> {
|
||||||
let eventsMap = dom[internalKeys.nonDelegatedEvents];
|
let eventsMap = dom[INTERNAL_NONDELEGATEEVENTS];
|
||||||
if (!eventsMap) {
|
if (!eventsMap) {
|
||||||
eventsMap = new Map();
|
eventsMap = new Map();
|
||||||
dom[internalKeys.nonDelegatedEvents] = eventsMap;
|
dom[INTERNAL_NONDELEGATEEVENTS] = eventsMap;
|
||||||
}
|
}
|
||||||
return eventsMap;
|
return eventsMap;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ import {
|
||||||
createDom,
|
createDom,
|
||||||
} from './utils/DomCreator';
|
} from './utils/DomCreator';
|
||||||
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
import { getSelectionInfo, resetSelectionRange, SelectionData } from './SelectionRangeHandler';
|
||||||
import { isElement, isComment, isDocument, isDocumentFragment, getDomTag, shouldAutoFocus } from './utils/Common';
|
import { shouldAutoFocus } from './utils/Common';
|
||||||
import { NSS } from './utils/DomCreator';
|
import { NSS } from './utils/DomCreator';
|
||||||
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
import { adjustStyleValue } from './DOMPropertiesHandler/StyleHandler';
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
|
||||||
// 应用diff更新Properties.
|
// 应用diff更新Properties.
|
||||||
// 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false.
|
// 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false.
|
||||||
if (type === 'input' && newProps.type === 'radio' && newProps.name != null && newProps.checked != null) {
|
if (type === 'input' && newProps.type === 'radio' && newProps.name != null && newProps.checked != null) {
|
||||||
updateCommonProp(element, 'checked', newProps.checked);
|
updateCommonProp(element, 'checked', newProps.checked, true);
|
||||||
}
|
}
|
||||||
const isNativeTag = isNativeElement(type, newProps);
|
const isNativeTag = isNativeElement(type, newProps);
|
||||||
updateDomProps(element, changeList, isNativeTag);
|
updateDomProps(element, changeList, isNativeTag);
|
||||||
|
|
|
@ -11,20 +11,18 @@ import { isEventProp, isNativeElement } from '../validators/ValidateProps';
|
||||||
function updateOneProp(dom, propName, isNativeTag, propVal?, isInit?: boolean) {
|
function updateOneProp(dom, propName, isNativeTag, propVal?, isInit?: boolean) {
|
||||||
if (propName === 'style') {
|
if (propName === 'style') {
|
||||||
setStyles(dom, propVal);
|
setStyles(dom, propVal);
|
||||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
|
||||||
dom.innerHTML = propVal.__html;
|
|
||||||
} else if (propName === 'children') { // 只处理纯文本子节点,其他children在VNode树中处理
|
|
||||||
const type = typeof propVal;
|
|
||||||
if (type === 'string') {
|
|
||||||
dom.textContent = propVal;
|
|
||||||
} else if (type === 'number') {
|
|
||||||
dom.textContent = propVal + ''; // 这种数字转字符串的方式效率最高
|
|
||||||
}
|
|
||||||
} else if (isEventProp(propName)) {
|
} else if (isEventProp(propName)) {
|
||||||
// 事件监听属性处理
|
// 事件监听属性处理
|
||||||
if (!allDelegatedHorizonEvents.has(propName)) {
|
if (!allDelegatedHorizonEvents.has(propName)) {
|
||||||
listenNonDelegatedEvent(propName, dom, propVal);
|
listenNonDelegatedEvent(propName, dom, propVal);
|
||||||
}
|
}
|
||||||
|
} else if (propName === 'children') { // 只处理纯文本子节点,其他children在VNode树中处理
|
||||||
|
const type = typeof propVal;
|
||||||
|
if (type === 'string' || type === 'number') {
|
||||||
|
dom.textContent = propVal;
|
||||||
|
}
|
||||||
|
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||||
|
dom.innerHTML = propVal.__html;
|
||||||
} else {
|
} else {
|
||||||
if (!isInit || (isInit && propVal != null)) {
|
if (!isInit || (isInit && propVal != null)) {
|
||||||
updateCommonProp(dom, propName, propVal, isNativeTag);
|
updateCommonProp(dom, propName, propVal, isNativeTag);
|
||||||
|
@ -40,10 +38,12 @@ export function setDomProps(
|
||||||
): void {
|
): void {
|
||||||
const isNativeTag = isNativeElement(tagName, props);
|
const isNativeTag = isNativeElement(tagName, props);
|
||||||
const keysOfProps = Object.keys(props);
|
const keysOfProps = Object.keys(props);
|
||||||
|
let propName;
|
||||||
for (let i = 0; i < keysOfProps.length; i++) {
|
let propVal;
|
||||||
const propName = keysOfProps[i];
|
const keyLength = keysOfProps.length;
|
||||||
const propVal = props[propName];
|
for (let i = 0; i < keyLength; i++) {
|
||||||
|
propName = keysOfProps[i];
|
||||||
|
propVal = props[propName];
|
||||||
|
|
||||||
updateOneProp(dom, propName, isNativeTag, propVal, true);
|
updateOneProp(dom, propName, isNativeTag, propVal, true);
|
||||||
}
|
}
|
||||||
|
@ -55,9 +55,12 @@ export function updateDomProps(
|
||||||
changeList: Array<any>,
|
changeList: Array<any>,
|
||||||
isNativeTag: boolean,
|
isNativeTag: boolean,
|
||||||
): void {
|
): void {
|
||||||
for (let i = 0; i < changeList.length; i++) {
|
const listLength = changeList.length;
|
||||||
const { propName, propVal } = changeList[i];
|
let propName;
|
||||||
|
let propVal;
|
||||||
|
for (let i = 0; i < listLength; i++) {
|
||||||
|
propName = changeList[i].propName;
|
||||||
|
propVal = changeList[i].propVal;
|
||||||
updateOneProp(dom, propName, isNativeTag, propVal);
|
updateOneProp(dom, propName, isNativeTag, propVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -73,19 +76,24 @@ export function compareProps(
|
||||||
const keysOfOldProps = Object.keys(oldProps);
|
const keysOfOldProps = Object.keys(oldProps);
|
||||||
const keysOfNewProps = Object.keys(newProps);
|
const keysOfNewProps = Object.keys(newProps);
|
||||||
|
|
||||||
|
const oldPropsLength = keysOfOldProps.length;
|
||||||
|
let propName;
|
||||||
|
let oldStyle;
|
||||||
|
let styleProps;
|
||||||
|
let styleProp;
|
||||||
// 找到旧属性中需要删除的属性
|
// 找到旧属性中需要删除的属性
|
||||||
for (let i = 0; i < keysOfOldProps.length; i++) {
|
for (let i = 0; i < oldPropsLength; i++) {
|
||||||
const propName = keysOfOldProps[i];
|
propName = keysOfOldProps[i];
|
||||||
// 新属性中包含该属性或者该属性为空值的属性不需要处理
|
// 新属性中包含该属性或者该属性为空值的属性不需要处理
|
||||||
if (keysOfNewProps.includes(propName) || oldProps[propName] == null) {
|
if (keysOfNewProps.includes(propName) || oldProps[propName] == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (propName === 'style') {
|
if (propName === 'style') {
|
||||||
const oldStyle = oldProps[propName];
|
oldStyle = oldProps[propName];
|
||||||
const styleProps = Object.keys(oldStyle);
|
styleProps = Object.keys(oldStyle);
|
||||||
for (let j = 0; j < styleProps.length; j++) {
|
for (let j = 0; j < styleProps.length; j++) {
|
||||||
const styleProp = styleProps[j];
|
styleProp = styleProps[j];
|
||||||
updatesForStyle[styleProp] = '';
|
updatesForStyle[styleProp] = '';
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
@ -110,11 +118,17 @@ export function compareProps(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let newPropValue;
|
||||||
|
let oldPropValue;
|
||||||
|
let oldStyleProps;
|
||||||
|
let newStyleProps;
|
||||||
|
let newHTML;
|
||||||
|
let oldHTML;
|
||||||
// 遍历新属性,获取新增和变更属性
|
// 遍历新属性,获取新增和变更属性
|
||||||
for (let i = 0; i < keysOfNewProps.length; i++) {
|
for (let i = 0; i < keysOfNewProps.length; i++) {
|
||||||
const propName = keysOfNewProps[i];
|
propName = keysOfNewProps[i];
|
||||||
const newPropValue = newProps[propName];
|
newPropValue = newProps[propName];
|
||||||
const oldPropValue = oldProps != null ? oldProps[propName] : null;
|
oldPropValue = oldProps != null ? oldProps[propName] : null;
|
||||||
|
|
||||||
if (newPropValue === oldPropValue || (newPropValue == null && oldPropValue == null)) {
|
if (newPropValue === oldPropValue || (newPropValue == null && oldPropValue == null)) {
|
||||||
// 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理
|
// 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理
|
||||||
|
@ -124,18 +138,18 @@ export function compareProps(
|
||||||
if (propName === 'style') {
|
if (propName === 'style') {
|
||||||
if (oldPropValue) { // 之前 style 属性有设置非空值
|
if (oldPropValue) { // 之前 style 属性有设置非空值
|
||||||
// 原来有这个 style,但现在没这个 style 了
|
// 原来有这个 style,但现在没这个 style 了
|
||||||
const oldStyleProps = Object.keys(oldPropValue);
|
oldStyleProps = Object.keys(oldPropValue);
|
||||||
for (let j = 0; j < oldStyleProps.length; j++) {
|
for (let j = 0; j < oldStyleProps.length; j++) {
|
||||||
const styleProp = oldStyleProps[j];
|
styleProp = oldStyleProps[j];
|
||||||
if (!newPropValue || !Object.prototype.hasOwnProperty.call(newPropValue, styleProp)) {
|
if (!newPropValue || !Object.prototype.hasOwnProperty.call(newPropValue, styleProp)) {
|
||||||
updatesForStyle[styleProp] = '';
|
updatesForStyle[styleProp] = '';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 现在有这个 style,但是和原来不相等
|
// 现在有这个 style,但是和原来不相等
|
||||||
const newStyleProps = newPropValue ? Object.keys(newPropValue) : [];
|
newStyleProps = newPropValue ? Object.keys(newPropValue) : [];
|
||||||
for (let j = 0; j < newStyleProps.length; j++) {
|
for (let j = 0; j < newStyleProps.length; j++) {
|
||||||
const styleProp = newStyleProps[j];
|
styleProp = newStyleProps[j];
|
||||||
if (oldPropValue[styleProp] !== newPropValue[styleProp]) {
|
if (oldPropValue[styleProp] !== newPropValue[styleProp]) {
|
||||||
updatesForStyle[styleProp] = newPropValue[styleProp];
|
updatesForStyle[styleProp] = newPropValue[styleProp];
|
||||||
}
|
}
|
||||||
|
@ -150,8 +164,8 @@ export function compareProps(
|
||||||
updatesForStyle = newPropValue;
|
updatesForStyle = newPropValue;
|
||||||
}
|
}
|
||||||
} else if (propName === 'dangerouslySetInnerHTML') {
|
} else if (propName === 'dangerouslySetInnerHTML') {
|
||||||
const newHTML = newPropValue ? newPropValue.__html : undefined;
|
newHTML = newPropValue ? newPropValue.__html : undefined;
|
||||||
const oldHTML = oldPropValue ? oldPropValue.__html : undefined;
|
oldHTML = oldPropValue ? oldPropValue.__html : undefined;
|
||||||
if (newHTML != null) {
|
if (newHTML != null) {
|
||||||
if (oldHTML !== newHTML) {
|
if (oldHTML !== newHTML) {
|
||||||
toBeUpdatedProps.push({
|
toBeUpdatedProps.push({
|
||||||
|
|
|
@ -29,7 +29,7 @@ function convertToLowerCase(str) {
|
||||||
* attrName 指代码中属性设置的属性名称(如 class)
|
* attrName 指代码中属性设置的属性名称(如 class)
|
||||||
* 多数情况 attrName 仅用作初始 DOM 节点对象使用,而 property 更多用于页面交互
|
* 多数情况 attrName 仅用作初始 DOM 节点对象使用,而 property 更多用于页面交互
|
||||||
*/
|
*/
|
||||||
export function updateCommonProp(dom: Element, attrName: string, value: any, isNativeTag: boolean = true) {
|
export function updateCommonProp(dom: Element, attrName: string, value: any, isNativeTag: boolean) {
|
||||||
const propDetails = getPropDetails(attrName);
|
const propDetails = getPropDetails(attrName);
|
||||||
|
|
||||||
if (isInvalidValue(attrName, value, propDetails, isNativeTag)) {
|
if (isInvalidValue(attrName, value, propDetails, isNativeTag)) {
|
||||||
|
|
|
@ -5,13 +5,6 @@ export const NSS = {
|
||||||
svg: 'http://www.w3.org/2000/svg',
|
svg: 'http://www.w3.org/2000/svg',
|
||||||
};
|
};
|
||||||
|
|
||||||
const div = document.createElement('div');
|
|
||||||
const span = document.createElement('span');
|
|
||||||
const tr = document.createElement('tr');
|
|
||||||
const td = document.createElement('td');
|
|
||||||
const a = document.createElement('a');
|
|
||||||
const p = document.createElement('p');
|
|
||||||
|
|
||||||
// 创建DOM元素
|
// 创建DOM元素
|
||||||
export function createDom(
|
export function createDom(
|
||||||
tagName: string,
|
tagName: string,
|
||||||
|
@ -23,18 +16,6 @@ export function createDom(
|
||||||
|
|
||||||
if (ns !== NSS.html) {
|
if (ns !== NSS.html) {
|
||||||
dom = document.createElementNS(ns, tagName);
|
dom = document.createElementNS(ns, tagName);
|
||||||
} else if (tagName === 'div') {
|
|
||||||
dom = div.cloneNode(false);
|
|
||||||
} else if (tagName === 'span') {
|
|
||||||
dom = span.cloneNode(false);
|
|
||||||
} else if (tagName === 'tr') {
|
|
||||||
dom = tr.cloneNode(false);
|
|
||||||
} else if (tagName === 'td') {
|
|
||||||
dom = td.cloneNode(false);
|
|
||||||
} else if (tagName === 'a') {
|
|
||||||
dom = a.cloneNode(false);
|
|
||||||
} else if (tagName === 'p') {
|
|
||||||
dom = p.cloneNode(false);
|
|
||||||
} else {
|
} else {
|
||||||
dom = document.createElement(tagName);
|
dom = document.createElement(tagName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,7 @@ export function updateInputValue(dom: HTMLInputElement, properties: IProperty) {
|
||||||
dom.value = String(value);
|
dom.value = String(value);
|
||||||
}
|
}
|
||||||
} else if (checked != null) {
|
} else if (checked != null) {
|
||||||
updateCommonProp(dom, 'checked', checked);
|
updateCommonProp(dom, 'checked', checked, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -29,17 +29,32 @@ let ctxOldContext: Object = {};
|
||||||
let ctxOldChange: Boolean = false;
|
let ctxOldChange: Boolean = false;
|
||||||
let ctxOldPreviousContext: Object = {};
|
let ctxOldPreviousContext: Object = {};
|
||||||
|
|
||||||
|
function setContext(vNode: VNode, contextName, value) {
|
||||||
|
if (vNode.contexts === null) {
|
||||||
|
vNode.contexts = {
|
||||||
|
[contextName]: value,
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
vNode.contexts[contextName] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function getContext(vNode: VNode, contextName) {
|
||||||
|
if (vNode.contexts !== null) {
|
||||||
|
return vNode.contexts[contextName];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// capture阶段设置
|
// capture阶段设置
|
||||||
function setNamespaceCtx(vNode: VNode, dom?: Container) {
|
function setNamespaceCtx(vNode: VNode, dom?: Container) {
|
||||||
const nextContext = getNSCtx(ctxNamespace, vNode.type, dom);
|
const nextContext = getNSCtx(ctxNamespace, vNode.type, dom);
|
||||||
|
|
||||||
vNode.setContext(CTX_NAMESPACE, ctxNamespace);
|
setContext(vNode, CTX_NAMESPACE, ctxNamespace);
|
||||||
ctxNamespace = nextContext;
|
ctxNamespace = nextContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
// bubble阶段恢复
|
// bubble阶段恢复
|
||||||
function resetNamespaceCtx(vNode: VNode) {
|
function resetNamespaceCtx(vNode: VNode) {
|
||||||
ctxNamespace = vNode.getContext(CTX_NAMESPACE);
|
ctxNamespace = getContext(vNode, CTX_NAMESPACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNamespaceCtx(): string {
|
function getNamespaceCtx(): string {
|
||||||
|
@ -49,14 +64,14 @@ function getNamespaceCtx(): string {
|
||||||
function setContextCtx<T>(providerVNode: VNode, nextValue: T) {
|
function setContextCtx<T>(providerVNode: VNode, nextValue: T) {
|
||||||
const context: ContextType<T> = providerVNode.type._context;
|
const context: ContextType<T> = providerVNode.type._context;
|
||||||
|
|
||||||
providerVNode.setContext(CTX_CONTEXT, context.value);
|
setContext(providerVNode, CTX_CONTEXT, context.value);
|
||||||
context.value = nextValue;
|
context.value = nextValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetContextCtx(providerVNode: VNode) {
|
function resetContextCtx(providerVNode: VNode) {
|
||||||
const context: ContextType<any> = providerVNode.type._context;
|
const context: ContextType<any> = providerVNode.type._context;
|
||||||
|
|
||||||
context.value = providerVNode.getContext(CTX_CONTEXT);
|
context.value = getContext(providerVNode, CTX_CONTEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在局部更新时,恢复父节点的context
|
// 在局部更新时,恢复父节点的context
|
||||||
|
@ -74,11 +89,11 @@ function recoverParentsContextCtx(vNode: VNode) {
|
||||||
|
|
||||||
// ctxOldContext是 旧context提供者的context
|
// ctxOldContext是 旧context提供者的context
|
||||||
function setVNodeOldContext(providerVNode: VNode, context: Object) {
|
function setVNodeOldContext(providerVNode: VNode, context: Object) {
|
||||||
providerVNode.setContext(CTX_OLD_CONTEXT, context);
|
setContext(providerVNode, CTX_OLD_CONTEXT, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVNodeOldContext(vNode: VNode) {
|
function getVNodeOldContext(vNode: VNode) {
|
||||||
return vNode.getContext(CTX_OLD_CONTEXT);
|
return getContext(vNode, CTX_OLD_CONTEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setOldContextCtx(providerVNode: VNode, context: Object) {
|
function setOldContextCtx(providerVNode: VNode, context: Object) {
|
||||||
|
@ -95,11 +110,11 @@ function resetOldContextCtx(vNode: VNode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setVNodeOldPreviousContext(providerVNode: VNode, context: Object) {
|
function setVNodeOldPreviousContext(providerVNode: VNode, context: Object) {
|
||||||
providerVNode.setContext(CTX_OLD_PREVIOUS_CONTEXT, context);
|
setContext(providerVNode, CTX_OLD_PREVIOUS_CONTEXT, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getVNodeOldPreviousContext(vNode: VNode) {
|
function getVNodeOldPreviousContext(vNode: VNode) {
|
||||||
return vNode.getContext(CTX_OLD_PREVIOUS_CONTEXT);
|
return getContext(vNode, CTX_OLD_PREVIOUS_CONTEXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
function setOldPreviousContextCtx(context: Object) {
|
function setOldPreviousContextCtx(context: Object) {
|
||||||
|
@ -111,7 +126,7 @@ function getOldPreviousContextCtx() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function setContextChangeCtx(providerVNode: VNode, didChange: boolean) {
|
function setContextChangeCtx(providerVNode: VNode, didChange: boolean) {
|
||||||
providerVNode.setContext(CTX_OLD_CHANGE, didChange);
|
setContext(providerVNode, CTX_OLD_CHANGE, didChange);
|
||||||
ctxOldChange = didChange;
|
ctxOldChange = didChange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +135,7 @@ function getContextChangeCtx() {
|
||||||
}
|
}
|
||||||
|
|
||||||
function resetContextChangeCtx(vNode: VNode) {
|
function resetContextChangeCtx(vNode: VNode) {
|
||||||
ctxOldChange = vNode.getContext(CTX_OLD_CHANGE);
|
ctxOldChange = getContext(vNode, CTX_OLD_CHANGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
export {
|
export {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import type {VNode} from './Types';
|
||||||
import type {Update} from './UpdateHandler';
|
import type {Update} from './UpdateHandler';
|
||||||
|
|
||||||
import {ClassComponent, TreeRoot} from './vnode/VNodeTags';
|
import {ClassComponent, TreeRoot} from './vnode/VNodeTags';
|
||||||
import {FlagUtils, Interrupted} from './vnode/VNodeFlags';
|
import {FlagUtils, Interrupted, DidCapture, InitFlag} from './vnode/VNodeFlags';
|
||||||
import {newUpdate, UpdateState, pushUpdate} from './UpdateHandler';
|
import {newUpdate, UpdateState, pushUpdate} from './UpdateHandler';
|
||||||
import {launchUpdateFromVNode, tryRenderFromRoot} from './TreeBuilder';
|
import {launchUpdateFromVNode, tryRenderFromRoot} from './TreeBuilder';
|
||||||
import {setRootThrowError} from './submit/Submit';
|
import {setRootThrowError} from './submit/Submit';
|
||||||
|
@ -99,7 +99,7 @@ export function handleRenderThrowError(
|
||||||
const ctor = vNode.type;
|
const ctor = vNode.type;
|
||||||
const instance = vNode.realNode;
|
const instance = vNode.realNode;
|
||||||
if (
|
if (
|
||||||
!vNode.flags.DidCapture &&
|
(vNode.flags & DidCapture) === InitFlag &&
|
||||||
(
|
(
|
||||||
typeof ctor.getDerivedStateFromError === 'function' ||
|
typeof ctor.getDerivedStateFromError === 'function' ||
|
||||||
(instance !== null && typeof instance.componentDidCatch === 'function')
|
(instance !== null && typeof instance.componentDidCatch === 'function')
|
||||||
|
|
|
@ -3,7 +3,7 @@ import type { VNode } from './Types';
|
||||||
import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue';
|
import { callRenderQueueImmediate, pushRenderCallback } from './taskExecutor/RenderQueue';
|
||||||
import { updateVNode } from './vnode/VNodeCreator';
|
import { updateVNode } from './vnode/VNodeCreator';
|
||||||
import { TreeRoot } from './vnode/VNodeTags';
|
import { TreeRoot } from './vnode/VNodeTags';
|
||||||
import { FlagUtils } from './vnode/VNodeFlags';
|
import { FlagUtils, InitFlag, Interrupted } from './vnode/VNodeFlags';
|
||||||
import { captureVNode } from './render/BaseComponent';
|
import { captureVNode } from './render/BaseComponent';
|
||||||
import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit';
|
import { checkLoopingUpdateLimit, submitToRender } from './submit/Submit';
|
||||||
import { runAsyncEffects } from './submit/HookEffectHandler';
|
import { runAsyncEffects } from './submit/HookEffectHandler';
|
||||||
|
@ -18,7 +18,7 @@ import {
|
||||||
setProcessingClassVNode,
|
setProcessingClassVNode,
|
||||||
setStartVNode
|
setStartVNode
|
||||||
} from './GlobalVar';
|
} from './GlobalVar';
|
||||||
import { findDomParent, getSiblingVNode } from './vnode/VNodeUtils';
|
import { findDomParent } from './vnode/VNodeUtils';
|
||||||
import {
|
import {
|
||||||
ByAsync,
|
ByAsync,
|
||||||
BySync,
|
BySync,
|
||||||
|
@ -86,13 +86,13 @@ function bubbleVNode(vNode: VNode): void {
|
||||||
do {
|
do {
|
||||||
const parent = node.parent;
|
const parent = node.parent;
|
||||||
|
|
||||||
if (!node.flags.Interrupted) { // vNode没有抛出异常
|
if ((node.flags & Interrupted) === InitFlag) { // vNode没有抛出异常
|
||||||
componentRenders[node.tag].bubbleRender(node);
|
componentRenders[node.tag].bubbleRender(node);
|
||||||
|
|
||||||
// 设置node的childShouldUpdate属性
|
// 设置node的childShouldUpdate属性
|
||||||
updateChildShouldUpdate(node);
|
updateChildShouldUpdate(node);
|
||||||
|
|
||||||
if (parent !== null && node !== getStartVNode() && !parent.flags.Interrupted) {
|
if (parent !== null && node !== getStartVNode() && (parent.flags & Interrupted) === InitFlag) {
|
||||||
collectDirtyNodes(node, parent);
|
collectDirtyNodes(node, parent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ function bubbleVNode(vNode: VNode): void {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const siblingVNode = getSiblingVNode(node);
|
const siblingVNode = node.next;
|
||||||
if (siblingVNode !== null) { // 有兄弟vNode
|
if (siblingVNode !== null) { // 有兄弟vNode
|
||||||
processing = siblingVNode;
|
processing = siblingVNode;
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -9,10 +9,6 @@ export function isTextType(newChild: any) {
|
||||||
return typeof newChild === 'string' || typeof newChild === 'number';
|
return typeof newChild === 'string' || typeof newChild === 'number';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isArrayType(newChild: any) {
|
|
||||||
return Array.isArray(newChild);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isIteratorType(newChild: any) {
|
export function isIteratorType(newChild: any) {
|
||||||
return (typeof Symbol === 'function' && newChild[Symbol.iterator]) || newChild['@@iterator'];
|
return (typeof Symbol === 'function' && newChild[Symbol.iterator]) || newChild['@@iterator'];
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,11 +7,10 @@ import {
|
||||||
isSameType,
|
isSameType,
|
||||||
getIteratorFn,
|
getIteratorFn,
|
||||||
isTextType,
|
isTextType,
|
||||||
isArrayType,
|
|
||||||
isIteratorType,
|
isIteratorType,
|
||||||
isObjectType,
|
isObjectType,
|
||||||
} from './DiffTools';
|
} from './DiffTools';
|
||||||
import {getSiblingVNode, travelChildren} from '../vnode/VNodeUtils';
|
import { travelChildren } from '../vnode/VNodeUtils';
|
||||||
|
|
||||||
enum DiffCategory {
|
enum DiffCategory {
|
||||||
TEXT_NODE = 'TEXT_NODE',
|
TEXT_NODE = 'TEXT_NODE',
|
||||||
|
@ -60,7 +59,7 @@ function checkCanReuseNode(oldNode: VNode | null, newChild: any): boolean {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isObjectType(newChild)) {
|
if (isObjectType(newChild)) {
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (Array.isArray(newChild) || isIteratorType(newChild)) {
|
||||||
return oldKey === null;
|
return oldKey === null;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
|
@ -79,7 +78,7 @@ function getNodeType(newChild: any): string | null {
|
||||||
return DiffCategory.TEXT_NODE;
|
return DiffCategory.TEXT_NODE;
|
||||||
}
|
}
|
||||||
if (isObjectType(newChild)) {
|
if (isObjectType(newChild)) {
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (Array.isArray(newChild) || isIteratorType(newChild)) {
|
||||||
return DiffCategory.ARR_NODE;
|
return DiffCategory.ARR_NODE;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
|
@ -200,7 +199,7 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
||||||
return nodeMap.get(newIdx) || null;
|
return nodeMap.get(newIdx) || null;
|
||||||
}
|
}
|
||||||
if (isObjectType(newChild)) {
|
if (isObjectType(newChild)) {
|
||||||
if (isArrayType(newChild) || isIteratorType(newChild)) {
|
if (Array.isArray(newChild) || isIteratorType(newChild)) {
|
||||||
return nodeMap.get(newIdx) || null;
|
return nodeMap.get(newIdx) || null;
|
||||||
}
|
}
|
||||||
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
if (newChild.vtype === TYPE_COMMON_ELEMENT || newChild.vtype === TYPE_PORTAL) {
|
||||||
|
@ -216,11 +215,11 @@ function setCIndex(vNode: VNode, idx: number) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// diff数组类型的节点,核心算法
|
// diff数组类型的节点,核心算法
|
||||||
function diffArrayNodes(
|
function diffArrayNodesHandler(
|
||||||
parentNode: VNode,
|
parentNode: VNode,
|
||||||
firstChild: VNode | null,
|
firstChild: VNode | null,
|
||||||
newChildren: Array<any>,
|
newChildren: Array<any>,
|
||||||
isComparing: boolean = true
|
isComparing: boolean
|
||||||
): VNode | null {
|
): VNode | null {
|
||||||
let resultingFirstChild: VNode | null = null;
|
let resultingFirstChild: VNode | null = null;
|
||||||
|
|
||||||
|
@ -242,6 +241,8 @@ function diffArrayNodes(
|
||||||
prevNewNode = newNode;
|
prevNewNode = newNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let canBeReuse;
|
||||||
|
let newNode;
|
||||||
// 1. 从左侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
// 1. 从左侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
||||||
for (; oldNode !== null && leftIdx < newChildren.length; leftIdx++) {
|
for (; oldNode !== null && leftIdx < newChildren.length; leftIdx++) {
|
||||||
if (oldNode.eIndex > leftIdx) {
|
if (oldNode.eIndex > leftIdx) {
|
||||||
|
@ -249,17 +250,17 @@ function diffArrayNodes(
|
||||||
nextOldNode = oldNode;
|
nextOldNode = oldNode;
|
||||||
oldNode = null;
|
oldNode = null;
|
||||||
} else {
|
} else {
|
||||||
nextOldNode = getSiblingVNode(oldNode);
|
nextOldNode = oldNode.next;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx]);
|
canBeReuse = checkCanReuseNode(oldNode, newChildren[leftIdx]);
|
||||||
// 不能复用,break
|
// 不能复用,break
|
||||||
if (!canBeReuse) {
|
if (!canBeReuse) {
|
||||||
oldNode = oldNode ?? nextOldNode;
|
oldNode = oldNode ?? nextOldNode;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], oldNode);
|
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNode);
|
||||||
// 没有生成新节点,break
|
// 没有生成新节点,break
|
||||||
if (!newNode) {
|
if (!newNode) {
|
||||||
oldNode = oldNode ?? nextOldNode;
|
oldNode = oldNode ?? nextOldNode;
|
||||||
|
@ -287,19 +288,20 @@ function diffArrayNodes(
|
||||||
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
|
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
|
||||||
|
|
||||||
// 2. 从右侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
// 2. 从右侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
||||||
|
let rightOldNode;
|
||||||
for (; rightIdx > leftIdx; rightIdx--) {
|
for (; rightIdx > leftIdx; rightIdx--) {
|
||||||
const rightOldNode = rightRemainingOldChildren[rightOldIndex];
|
rightOldNode = rightRemainingOldChildren[rightOldIndex];
|
||||||
if (rightOldIndex < 0 || rightOldNode === null) {
|
if (rightOldIndex < 0 || rightOldNode === null) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const canBeReuse = checkCanReuseNode(rightOldNode, newChildren[rightIdx - 1]);
|
canBeReuse = checkCanReuseNode(rightOldNode, newChildren[rightIdx - 1]);
|
||||||
// 不能复用,break
|
// 不能复用,break
|
||||||
if (!canBeReuse) {
|
if (!canBeReuse) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
const newNode = getNewNode(parentNode, newChildren[rightIdx - 1], rightOldNode);
|
newNode = getNewNode(parentNode, newChildren[rightIdx - 1], rightOldNode);
|
||||||
// 没有生成新节点,break
|
// 没有生成新节点,break
|
||||||
if (newNode === null) {
|
if (newNode === null) {
|
||||||
break;
|
break;
|
||||||
|
@ -346,7 +348,7 @@ function diffArrayNodes(
|
||||||
// 4. 新节点还有一部分,但是老节点已经没有了
|
// 4. 新节点还有一部分,但是老节点已经没有了
|
||||||
if (oldNode === null) {
|
if (oldNode === null) {
|
||||||
for (; leftIdx < rightIdx; leftIdx++) {
|
for (; leftIdx < rightIdx; leftIdx++) {
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], null);
|
newNode = getNewNode(parentNode, newChildren[leftIdx], null);
|
||||||
|
|
||||||
if (newNode !== null) {
|
if (newNode !== null) {
|
||||||
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing);
|
theLastPosition = setVNodeAdditionFlag(newNode, theLastPosition, isComparing);
|
||||||
|
@ -372,9 +374,11 @@ function diffArrayNodes(
|
||||||
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
const preIndex: Array<number> = []; // 贪心算法在替换的过程中会使得数组不正确,通过记录preIndex找到正确值
|
||||||
const reuseNodes = []; // 记录复用的 VNode
|
const reuseNodes = []; // 记录复用的 VNode
|
||||||
let i = 0;
|
let i = 0;
|
||||||
|
let oldNodeFromMap;
|
||||||
|
let last;
|
||||||
for (; leftIdx < rightIdx; leftIdx++) {
|
for (; leftIdx < rightIdx; leftIdx++) {
|
||||||
const oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
|
oldNodeFromMap = getOldNodeFromMap(leftChildrenMap, leftIdx, newChildren[leftIdx]);
|
||||||
const newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
|
newNode = getNewNode(parentNode, newChildren[leftIdx], oldNodeFromMap);
|
||||||
if (newNode !== null) {
|
if (newNode !== null) {
|
||||||
if (isComparing && !newNode.isCreated) {
|
if (isComparing && !newNode.isCreated) {
|
||||||
// 从Map删除,后面不会deleteVNode
|
// 从Map删除,后面不会deleteVNode
|
||||||
|
@ -384,7 +388,7 @@ function diffArrayNodes(
|
||||||
if (oldNodeFromMap !== null) {
|
if (oldNodeFromMap !== null) {
|
||||||
let eIndex = newNode.eIndex;
|
let eIndex = newNode.eIndex;
|
||||||
eIndexes.push(eIndex);
|
eIndexes.push(eIndex);
|
||||||
const last: number | undefined = 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);
|
||||||
|
@ -462,16 +466,6 @@ function setVNodesCIndex(startChild: VNode, startIdx: number) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新节点是数组类型
|
|
||||||
function diffArrayNodesHandler(
|
|
||||||
parentNode: VNode,
|
|
||||||
firstChild: VNode | null,
|
|
||||||
newChildren: Array<any>,
|
|
||||||
isComparing: boolean = true
|
|
||||||
): VNode | null {
|
|
||||||
return diffArrayNodes(parentNode, firstChild, newChildren, isComparing);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 新节点是迭代器类型
|
// 新节点是迭代器类型
|
||||||
function diffIteratorNodesHandler(
|
function diffIteratorNodesHandler(
|
||||||
parentNode: VNode,
|
parentNode: VNode,
|
||||||
|
@ -490,7 +484,7 @@ function diffIteratorNodesHandler(
|
||||||
result = iteratorObj.next();
|
result = iteratorObj.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
return diffArrayNodes(parentNode, firstChild, childrenArray, isComparing);
|
return diffArrayNodesHandler(parentNode, firstChild, childrenArray, isComparing);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新节点是字符串类型
|
// 新节点是字符串类型
|
||||||
|
@ -552,13 +546,13 @@ function diffObjectNodeHandler(
|
||||||
// 可以复用
|
// 可以复用
|
||||||
if (canReuseNode.tag === Fragment && newChild.type === TYPE_FRAGMENT) {
|
if (canReuseNode.tag === Fragment && newChild.type === TYPE_FRAGMENT) {
|
||||||
resultNode = updateVNode(canReuseNode, newChild.props.children);
|
resultNode = updateVNode(canReuseNode, newChild.props.children);
|
||||||
startDelVNode = getSiblingVNode(canReuseNode);
|
startDelVNode = canReuseNode.next;
|
||||||
resultNode.next = null;
|
resultNode.next = null;
|
||||||
} else if (isSameType(canReuseNode, newChild)) {
|
} else if (isSameType(canReuseNode, newChild)) {
|
||||||
resultNode = updateVNode(canReuseNode, newChild.props);
|
resultNode = updateVNode(canReuseNode, newChild.props);
|
||||||
resultNode.ref = newChild.ref;
|
resultNode.ref = newChild.ref;
|
||||||
resultNode.belongClassVNode = newChild.belongClassVNode;
|
resultNode.belongClassVNode = newChild.belongClassVNode;
|
||||||
startDelVNode = getSiblingVNode(resultNode);
|
startDelVNode = resultNode.next;
|
||||||
resultNode.next = null;
|
resultNode.next = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -578,7 +572,7 @@ function diffObjectNodeHandler(
|
||||||
// 可以复用
|
// 可以复用
|
||||||
if (canReuseNode.tag === DomPortal && canReuseNode.outerDom === newChild.outerDom) {
|
if (canReuseNode.tag === DomPortal && canReuseNode.outerDom === newChild.outerDom) {
|
||||||
resultNode = updateVNode(canReuseNode, newChild.children || []);
|
resultNode = updateVNode(canReuseNode, newChild.children || []);
|
||||||
startDelVNode = getSiblingVNode(canReuseNode);
|
startDelVNode = canReuseNode.next;
|
||||||
resultNode.next = null;
|
resultNode.next = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -629,7 +623,7 @@ export function createChildrenByDiff(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. newChild是数组类型
|
// 3. newChild是数组类型
|
||||||
if (isArrayType(newChild)) {
|
if (Array.isArray(newChild)) {
|
||||||
return diffArrayNodesHandler(parentNode, firstChild, newChild, isComparing);
|
return diffArrayNodesHandler(parentNode, firstChild, newChild, isComparing);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -66,9 +66,7 @@ export function captureVNode(processing: VNode): VNode | null {
|
||||||
|
|
||||||
// 创建孩子节点
|
// 创建孩子节点
|
||||||
export function createVNodeChildren(processing: VNode, nextChildren: any) {
|
export function createVNodeChildren(processing: VNode, nextChildren: any) {
|
||||||
const isComparing = !processing.isCreated;
|
return createChildrenByDiff(processing, processing.child, nextChildren, !processing.isCreated);
|
||||||
|
|
||||||
return createChildrenByDiff(processing, processing.child, nextChildren, isComparing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function markRef(processing: VNode) {
|
export function markRef(processing: VNode) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import {
|
||||||
markComponentDidUpdate,
|
markComponentDidUpdate,
|
||||||
markGetSnapshotBeforeUpdate,
|
markGetSnapshotBeforeUpdate,
|
||||||
} from './class/ClassLifeCycleProcessor';
|
} from './class/ClassLifeCycleProcessor';
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils, DidCapture } from '../vnode/VNodeFlags';
|
||||||
import { createVNodeChildren, markRef } from './BaseComponent';
|
import { createVNodeChildren, markRef } from './BaseComponent';
|
||||||
import {
|
import {
|
||||||
createUpdateArray,
|
createUpdateArray,
|
||||||
|
@ -73,7 +73,7 @@ function createChildren(clazz: any, processing: VNode) {
|
||||||
processing.state = processing.realNode.state;
|
processing.state = processing.realNode.state;
|
||||||
|
|
||||||
const inst = processing.realNode;
|
const inst = processing.realNode;
|
||||||
const isCatchError = processing.flags.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'
|
||||||
|
@ -122,7 +122,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
|
||||||
const newContext = getCurrentContext(clazz, processing);
|
const newContext = getCurrentContext(clazz, processing);
|
||||||
|
|
||||||
// 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props
|
// 子节点抛出异常时,如果本class是个捕获异常的处理节点,这时候oldProps是null,所以需要使用props
|
||||||
let oldProps = processing.flags.DidCapture ? processing.props : processing.oldProps;
|
let oldProps = (processing.flags & DidCapture) === DidCapture ? processing.props : processing.oldProps;
|
||||||
if (processing.isLazyComponent) {
|
if (processing.isLazyComponent) {
|
||||||
oldProps = mergeDefaultProps(processing.type, oldProps);
|
oldProps = mergeDefaultProps(processing.type, oldProps);
|
||||||
}
|
}
|
||||||
|
@ -161,7 +161,7 @@ export function captureClassComponent(processing: VNode, clazz: any, nextProps:
|
||||||
inst.props = nextProps;
|
inst.props = nextProps;
|
||||||
}
|
}
|
||||||
// 如果捕获了 error,必须更新
|
// 如果捕获了 error,必须更新
|
||||||
const isCatchError = processing.flags.DidCapture;
|
const isCatchError = (processing.flags & DidCapture) === DidCapture;
|
||||||
shouldUpdate = isCatchError || shouldUpdate;
|
shouldUpdate = isCatchError || shouldUpdate;
|
||||||
|
|
||||||
// 更新ref
|
// 更新ref
|
||||||
|
|
|
@ -15,7 +15,7 @@ import {
|
||||||
import { FlagUtils } from '../vnode/VNodeFlags';
|
import { FlagUtils } from '../vnode/VNodeFlags';
|
||||||
import { createVNodeChildren, markRef } from './BaseComponent';
|
import { createVNodeChildren, markRef } from './BaseComponent';
|
||||||
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
|
import { DomComponent, DomPortal, DomText } from '../vnode/VNodeTags';
|
||||||
import {getFirstChild, travelVNodeTree} from '../vnode/VNodeUtils';
|
import { travelVNodeTree } from '../vnode/VNodeUtils';
|
||||||
|
|
||||||
function updateDom(
|
function updateDom(
|
||||||
processing: VNode,
|
processing: VNode,
|
||||||
|
@ -50,24 +50,6 @@ function updateDom(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 把dom类型的子节点append到parent dom中
|
|
||||||
function appendAllChildren(parent: Element, processing: VNode) {
|
|
||||||
const vNode = processing.child;
|
|
||||||
if (vNode === null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 向下递归它的子节点,查找所有终端节点。
|
|
||||||
travelVNodeTree(vNode, node => {
|
|
||||||
if (node.tag === DomComponent || node.tag === DomText) {
|
|
||||||
appendChildElement(parent, node.realNode);
|
|
||||||
}
|
|
||||||
}, node =>
|
|
||||||
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
|
||||||
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
|
|
||||||
, processing);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function bubbleRender(processing: VNode) {
|
export function bubbleRender(processing: VNode) {
|
||||||
resetNamespaceCtx(processing);
|
resetNamespaceCtx(processing);
|
||||||
|
|
||||||
|
@ -95,7 +77,19 @@ export function bubbleRender(processing: VNode) {
|
||||||
processing,
|
processing,
|
||||||
);
|
);
|
||||||
|
|
||||||
appendAllChildren(dom, processing);
|
// 把dom类型的子节点append到parent dom中
|
||||||
|
const vNode = processing.child;
|
||||||
|
if (vNode !== null) {
|
||||||
|
// 向下递归它的子节点,查找所有终端节点。
|
||||||
|
travelVNodeTree(vNode, node => {
|
||||||
|
if (node.tag === DomComponent || node.tag === DomText) {
|
||||||
|
appendChildElement(dom, node.realNode);
|
||||||
|
}
|
||||||
|
}, node =>
|
||||||
|
// 已经append到父节点,或者是DomPortal都不需要处理child了
|
||||||
|
node.tag === DomComponent || node.tag === DomText || node.tag === DomPortal
|
||||||
|
, processing);
|
||||||
|
}
|
||||||
|
|
||||||
processing.realNode = dom;
|
processing.realNode = dom;
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ import {
|
||||||
SuspenseComponent,
|
SuspenseComponent,
|
||||||
MemoComponent,
|
MemoComponent,
|
||||||
} from '../vnode/VNodeTags';
|
} from '../vnode/VNodeTags';
|
||||||
import { FlagUtils, ResetText, Clear } from '../vnode/VNodeFlags';
|
import { FlagUtils, ResetText, Clear, Update } from '../vnode/VNodeFlags';
|
||||||
import { mergeDefaultProps } from '../render/LazyComponent';
|
import { mergeDefaultProps } from '../render/LazyComponent';
|
||||||
import {
|
import {
|
||||||
submitDomUpdate,
|
submitDomUpdate,
|
||||||
|
@ -97,7 +97,7 @@ function callAfterSubmitLifeCycles(
|
||||||
}
|
}
|
||||||
case ClassComponent: {
|
case ClassComponent: {
|
||||||
const instance = vNode.realNode;
|
const instance = vNode.realNode;
|
||||||
if (vNode.flags.Update) {
|
if ((vNode.flags & Update) === Update) {
|
||||||
if (vNode.isCreated) {
|
if (vNode.isCreated) {
|
||||||
instance.componentDidMount();
|
instance.componentDidMount();
|
||||||
} else {
|
} else {
|
||||||
|
@ -124,7 +124,7 @@ function callAfterSubmitLifeCycles(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case DomComponent: {
|
case DomComponent: {
|
||||||
if (vNode.isCreated && vNode.flags.Update) {
|
if (vNode.isCreated && (vNode.flags & Update) === Update) {
|
||||||
// button、input、select、textarea、如果有 autoFocus 属性需要focus
|
// button、input、select、textarea、如果有 autoFocus 属性需要focus
|
||||||
if (shouldAutoFocus(vNode.type, vNode.props)) {
|
if (shouldAutoFocus(vNode.type, vNode.props)) {
|
||||||
vNode.realNode.focus();
|
vNode.realNode.focus();
|
||||||
|
@ -222,7 +222,7 @@ function unmountNestedVNodes(vNode: VNode): void {
|
||||||
function submitAddition(vNode: VNode): void {
|
function submitAddition(vNode: VNode): void {
|
||||||
const { parent, parentDom } = findDomParent(vNode);
|
const { parent, parentDom } = findDomParent(vNode);
|
||||||
|
|
||||||
if (parent.flags.ResetText) {
|
if ((vNode.flags & ResetText) === ResetText) {
|
||||||
// 在insert之前先reset
|
// 在insert之前先reset
|
||||||
clearText(parentDom);
|
clearText(parentDom);
|
||||||
FlagUtils.removeFlag(parent, ResetText);
|
FlagUtils.removeFlag(parent, ResetText);
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
import type {VNode} from '../Types';
|
import type {VNode} from '../Types';
|
||||||
|
|
||||||
import {callRenderQueueImmediate} from '../taskExecutor/RenderQueue';
|
import {FlagUtils, Addition, Snapshot, ResetText, Ref, Update, Deletion, Clear, Callback} from '../vnode/VNodeFlags';
|
||||||
import {throwIfTrue} from '../utils/throwIfTrue';
|
|
||||||
import {FlagUtils, Addition as AdditionFlag} from '../vnode/VNodeFlags';
|
|
||||||
import {prepareForSubmit, resetAfterSubmit} from '../../dom/DOMOperator';
|
import {prepareForSubmit, resetAfterSubmit} from '../../dom/DOMOperator';
|
||||||
import {handleSubmitError} from '../ErrorHandler';
|
import {handleSubmitError} from '../ErrorHandler';
|
||||||
import {
|
import {
|
||||||
|
@ -91,7 +89,7 @@ export function submitToRender(treeRoot) {
|
||||||
function beforeSubmit(dirtyNodes: Array<VNode>) {
|
function beforeSubmit(dirtyNodes: Array<VNode>) {
|
||||||
dirtyNodes.forEach(node => {
|
dirtyNodes.forEach(node => {
|
||||||
try {
|
try {
|
||||||
if (node.flags.Snapshot) {
|
if ((node.flags & Snapshot) === Snapshot) {
|
||||||
callBeforeSubmitLifeCycles(node);
|
callBeforeSubmitLifeCycles(node);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
@ -103,35 +101,38 @@ function beforeSubmit(dirtyNodes: Array<VNode>) {
|
||||||
function submit(dirtyNodes: Array<VNode>) {
|
function submit(dirtyNodes: Array<VNode>) {
|
||||||
dirtyNodes.forEach(node => {
|
dirtyNodes.forEach(node => {
|
||||||
try {
|
try {
|
||||||
if (node.flags.ResetText) {
|
if ((node.flags & ResetText) === ResetText) {
|
||||||
submitResetTextContent(node);
|
submitResetTextContent(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.flags.Ref) {
|
if ((node.flags & Ref) === Ref) {
|
||||||
if (!node.isCreated) {
|
if (!node.isCreated) {
|
||||||
// 需要执行
|
// 需要执行
|
||||||
detachRef(node, true);
|
detachRef(node, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const {Addition, Update, Deletion, Clear} = node.flags;
|
const isAdd = (node.flags & Addition) === Addition;
|
||||||
if (Addition && Update) {
|
const isUpdate = (node.flags & Update) === Update;
|
||||||
|
if (isAdd && isUpdate) {
|
||||||
// Addition
|
// Addition
|
||||||
submitAddition(node);
|
submitAddition(node);
|
||||||
FlagUtils.removeFlag(node, AdditionFlag);
|
FlagUtils.removeFlag(node, Addition);
|
||||||
|
|
||||||
// Update
|
// Update
|
||||||
submitUpdate(node);
|
submitUpdate(node);
|
||||||
} else {
|
} else {
|
||||||
if (Addition) {
|
const isDeletion = (node.flags & Deletion) === Deletion;
|
||||||
|
const isClear = (node.flags & Clear) === Clear;
|
||||||
|
if (isAdd) {
|
||||||
submitAddition(node);
|
submitAddition(node);
|
||||||
FlagUtils.removeFlag(node, AdditionFlag);
|
FlagUtils.removeFlag(node, Addition);
|
||||||
} else if (Update) {
|
} else if (isUpdate) {
|
||||||
submitUpdate(node);
|
submitUpdate(node);
|
||||||
} else if (Deletion) {
|
} else if (isDeletion) {
|
||||||
submitDeletion(node);
|
submitDeletion(node);
|
||||||
}
|
}
|
||||||
if (Clear) {
|
if (isClear) {
|
||||||
submitClear(node);
|
submitClear(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,11 +145,11 @@ function submit(dirtyNodes: Array<VNode>) {
|
||||||
function afterSubmit(dirtyNodes: Array<VNode>) {
|
function afterSubmit(dirtyNodes: Array<VNode>) {
|
||||||
dirtyNodes.forEach(node => {
|
dirtyNodes.forEach(node => {
|
||||||
try {
|
try {
|
||||||
if (node.flags.Update || node.flags.Callback) {
|
if ((node.flags & Update) === Update || (node.flags & Callback) === Callback) {
|
||||||
callAfterSubmitLifeCycles(node);
|
callAfterSubmitLifeCycles(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (node.flags.Ref) {
|
if ((node.flags & Ref) === Ref) {
|
||||||
attachRef(node);
|
attachRef(node);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
/**
|
/**
|
||||||
* 虚拟DOM结构体
|
* 虚拟DOM结构体
|
||||||
*/
|
*/
|
||||||
import {TreeRoot} from './VNodeTags';
|
import { TreeRoot, FunctionComponent, ClassComponent, DomPortal, DomText, ContextConsumer, ForwardRef, SuspenseComponent, LazyComponent, ClsOrFunComponent, DomComponent, Fragment, ContextProvider, Profiler, MemoComponent, IncompleteClassComponent } from './VNodeTags';
|
||||||
import type { VNodeTag } from './VNodeTags';
|
import type { VNodeTag } from './VNodeTags';
|
||||||
import type { RefType, ContextType } from '../Types';
|
import type { RefType, ContextType } from '../Types';
|
||||||
import type { Hook } from '../hooks/HookType';
|
import type { Hook } from '../hooks/HookType';
|
||||||
|
import { InitFlag } from './VNodeFlags';
|
||||||
|
|
||||||
export class VNode {
|
export class VNode {
|
||||||
tag: VNodeTag;
|
tag: VNodeTag;
|
||||||
key: string | null; // 唯一标识符
|
key: string | null; // 唯一标识符
|
||||||
|
props: any; // 传给组件的props的值,类组件包含defaultProps,Lazy组件不包含
|
||||||
type: any = null;
|
type: any = null;
|
||||||
realNode: any = null; // 如果是类,则存放实例;如果是div这种,则存放真实DOM;
|
realNode: any; // 如果是类,则存放实例;如果是div这种,则存放真实DOM;
|
||||||
|
|
||||||
// 关系结构
|
// 关系结构
|
||||||
parent: VNode | null = null; // 父节点
|
parent: VNode | null = null; // 父节点
|
||||||
|
@ -20,21 +22,20 @@ export class VNode {
|
||||||
eIndex: number = 0; // HorizonElement在jsx中的位置,例如:jsx中的null不会生成vNode,所以eIndex和cIndex不一致
|
eIndex: number = 0; // HorizonElement在jsx中的位置,例如:jsx中的null不会生成vNode,所以eIndex和cIndex不一致
|
||||||
|
|
||||||
ref: RefType | ((handle: any) => void) | null = null; // 包裹一个函数,submit阶段使用,比如将外部useRef生成的对象赋值到ref上
|
ref: RefType | ((handle: any) => void) | null = null; // 包裹一个函数,submit阶段使用,比如将外部useRef生成的对象赋值到ref上
|
||||||
props: any; // 传给组件的props的值,类组件包含defaultProps,Lazy组件不包含
|
|
||||||
oldProps: any = null;
|
oldProps: any = null;
|
||||||
|
|
||||||
suspensePromises: any = null; // suspense组件的promise列表
|
suspensePromises: any; // suspense组件的promise列表
|
||||||
changeList: any = null; // DOM的变更列表
|
changeList: any; // DOM的变更列表
|
||||||
effectList: any[] | null = null; // useEffect 的更新数组
|
effectList: any[] | null; // useEffect 的更新数组
|
||||||
updates: any[] | null = null; // TreeRoot和ClassComponent使用的更新数组
|
updates: any[] | null; // TreeRoot和ClassComponent使用的更新数组
|
||||||
stateCallbacks: any[] | null = null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
|
stateCallbacks: any[] | null; // 存放存在setState的第二个参数和HorizonDOM.render的第三个参数所在的node数组
|
||||||
isForceUpdate: boolean = false; // 是否使用强制更新
|
isForceUpdate: boolean; // 是否使用强制更新
|
||||||
|
|
||||||
state: any = null; // ClassComponent和TreeRoot的状态
|
state: any; // ClassComponent和TreeRoot的状态
|
||||||
hooks: Array<Hook<any, any>> | null = null; // 保存hook
|
hooks: Array<Hook<any, any>> | null; // 保存hook
|
||||||
suspenseChildStatus: string = ''; // Suspense的Children是否显示
|
suspenseChildStatus: string = ''; // Suspense的Children是否显示
|
||||||
depContexts: Array<ContextType<any>> | null = null; // FunctionComponent和ClassComponent对context的依赖列表
|
depContexts: Array<ContextType<any>> | null; // FunctionComponent和ClassComponent对context的依赖列表
|
||||||
isDepContextChange: boolean = false; // context是否变更
|
isDepContextChange: boolean; // context是否变更
|
||||||
dirtyNodes: Array<VNode> | null = null; // 需要改动的节点数组
|
dirtyNodes: Array<VNode> | null = null; // 需要改动的节点数组
|
||||||
shouldUpdate: boolean = false;
|
shouldUpdate: boolean = false;
|
||||||
childShouldUpdate: boolean = false;
|
childShouldUpdate: boolean = false;
|
||||||
|
@ -42,40 +43,27 @@ export class VNode {
|
||||||
task: any;
|
task: any;
|
||||||
|
|
||||||
// 使用这个变量来记录修改前的值,用于恢复。
|
// 使用这个变量来记录修改前的值,用于恢复。
|
||||||
contexts = {};
|
contexts: any;
|
||||||
// 因为LazyComponent会修改tag和type属性,为了能识别,增加一个属性
|
// 因为LazyComponent会修改tag和type属性,为了能识别,增加一个属性
|
||||||
isLazyComponent: boolean = false;
|
isLazyComponent: boolean;
|
||||||
|
|
||||||
// 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType
|
// 因为LazyComponent会修改type属性,为了在diff中判断是否可以复用,需要增加一个lazyType
|
||||||
lazyType: any = null;
|
lazyType: any;
|
||||||
flags: {
|
flags = InitFlag;
|
||||||
Addition?: boolean;
|
clearChild: VNode | null;
|
||||||
Update?: boolean;
|
|
||||||
Deletion?: boolean;
|
|
||||||
ResetText?: boolean;
|
|
||||||
Callback?: boolean;
|
|
||||||
DidCapture?: boolean;
|
|
||||||
Ref?: boolean;
|
|
||||||
Snapshot?: boolean;
|
|
||||||
Interrupted?: boolean;
|
|
||||||
ShouldCapture?: boolean;
|
|
||||||
ForceUpdate?: boolean;
|
|
||||||
Clear?: boolean;
|
|
||||||
} = {};
|
|
||||||
clearChild: VNode | null = null;
|
|
||||||
// one tree相关属性
|
// one tree相关属性
|
||||||
isCreated: boolean = true;
|
isCreated: boolean = true;
|
||||||
oldHooks: Array<Hook<any, any>> | null = []; // 保存上一次执行的hook
|
oldHooks: Array<Hook<any, any>> | null; // 保存上一次执行的hook
|
||||||
oldState: any = null;
|
oldState: any;
|
||||||
oldRef: RefType | ((handle: any) => void) | null = null;
|
oldRef: RefType | ((handle: any) => void) | null = null;
|
||||||
suspenseChildThrow = false;
|
suspenseChildThrow: boolean;
|
||||||
oldSuspenseChildStatus: string = ''; // 上一次Suspense的Children是否显示
|
oldSuspenseChildStatus: string; // 上一次Suspense的Children是否显示
|
||||||
oldChild: VNode | null = null;
|
oldChild: VNode | null = null;
|
||||||
suspenseDidCapture: boolean = false; // suspense是否捕获了异常
|
suspenseDidCapture: boolean; // suspense是否捕获了异常
|
||||||
promiseResolve: boolean = false; // suspense的promise是否resolve
|
promiseResolve: boolean; // suspense的promise是否resolve
|
||||||
|
|
||||||
path: string = ''; // 保存从根到本节点的路径
|
path: string = ''; // 保存从根到本节点的路径
|
||||||
toUpdateNodes: Set<VNode> | null = null; // 保存要更新的节点
|
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
|
||||||
|
|
||||||
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode,处理ref的时候使用
|
||||||
|
|
||||||
|
@ -85,18 +73,80 @@ export class VNode {
|
||||||
|
|
||||||
this.props = props;
|
this.props = props;
|
||||||
|
|
||||||
// 根节点
|
switch (tag) {
|
||||||
if (tag === TreeRoot) {
|
case TreeRoot:
|
||||||
this.outerDom = outerDom;
|
this.outerDom = outerDom;
|
||||||
this.task = null;
|
this.task = null;
|
||||||
this.toUpdateNodes = new Set<VNode>();
|
this.toUpdateNodes = new Set<VNode>();
|
||||||
|
this.realNode = null;
|
||||||
|
this.updates = null;
|
||||||
|
this.stateCallbacks = null;
|
||||||
|
this.state = null;
|
||||||
|
this.oldState = null;
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case FunctionComponent:
|
||||||
|
this.effectList = null;
|
||||||
|
this.hooks = null;
|
||||||
|
this.depContexts = null;
|
||||||
|
this.isDepContextChange = false;
|
||||||
|
this.oldHooks = null;
|
||||||
|
break;
|
||||||
|
case ClassComponent:
|
||||||
|
this.realNode = null;
|
||||||
|
this.updates = null;
|
||||||
|
this.stateCallbacks = null;
|
||||||
|
this.isForceUpdate = false;
|
||||||
|
this.state = null;
|
||||||
|
this.depContexts = null;
|
||||||
|
this.isDepContextChange = false;
|
||||||
|
this.oldState = null;
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case ClsOrFunComponent:
|
||||||
|
this.realNode = null;
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case DomPortal:
|
||||||
|
this.realNode = null;
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case DomComponent:
|
||||||
|
this.realNode = null;
|
||||||
|
this.changeList = null;
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case DomText:
|
||||||
|
this.realNode = null;
|
||||||
|
break;
|
||||||
|
case SuspenseComponent:
|
||||||
|
this.realNode = null;
|
||||||
|
this.suspensePromises = null;
|
||||||
|
this.suspenseChildThrow = false;
|
||||||
|
this.suspenseDidCapture = false;
|
||||||
|
this.promiseResolve = false;
|
||||||
|
this.oldSuspenseChildStatus = '';
|
||||||
|
break;
|
||||||
|
case ContextProvider:
|
||||||
|
this.contexts = null;
|
||||||
|
break;
|
||||||
|
case MemoComponent:
|
||||||
|
this.effectList = null;
|
||||||
|
break;
|
||||||
|
case LazyComponent:
|
||||||
|
this.realNode = null;
|
||||||
|
this.stateCallbacks = null;
|
||||||
|
break;
|
||||||
|
case Fragment:
|
||||||
|
break;
|
||||||
|
case ContextConsumer:
|
||||||
|
break;
|
||||||
|
case ForwardRef:
|
||||||
|
break;
|
||||||
|
case Profiler:
|
||||||
|
break;
|
||||||
|
case IncompleteClassComponent:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setContext(contextName, value) {
|
|
||||||
this.contexts[contextName] = value;
|
|
||||||
}
|
|
||||||
getContext(contextName) {
|
|
||||||
return this.contexts[contextName];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,9 +133,8 @@ export function createUndeterminedVNode(type, key, props) {
|
||||||
vNode.type = type;
|
vNode.type = type;
|
||||||
vNode.shouldUpdate = true;
|
vNode.shouldUpdate = true;
|
||||||
|
|
||||||
// lazy类型的特殊处理
|
|
||||||
vNode.isLazyComponent = isLazy;
|
|
||||||
if (isLazy) {
|
if (isLazy) {
|
||||||
|
vNode.isLazyComponent = isLazy;
|
||||||
vNode.lazyType = type;
|
vNode.lazyType = type;
|
||||||
}
|
}
|
||||||
return vNode;
|
return vNode;
|
||||||
|
|
|
@ -4,97 +4,79 @@
|
||||||
|
|
||||||
import type { VNode } from '../Types';
|
import type { VNode } from '../Types';
|
||||||
|
|
||||||
|
|
||||||
|
export const InitFlag = /** */ 0b000000000000;
|
||||||
// vNode节点的flags
|
// vNode节点的flags
|
||||||
export const Addition = 'Addition';
|
export const Addition = /** */ 0b100000000000;
|
||||||
export const Update = 'Update';
|
export const Update = /** */ 0b010000000000;
|
||||||
export const Deletion = 'Deletion';
|
export const Deletion = /** */ 0b001000000000;
|
||||||
export const ResetText = 'ResetText';
|
export const ResetText =/** */ 0b000100000000;
|
||||||
export const Callback = 'Callback';
|
export const Callback = /** */ 0b000010000000;
|
||||||
export const DidCapture = 'DidCapture';
|
export const DidCapture =/** */ 0b000001000000;
|
||||||
export const Ref = 'Ref';
|
export const Ref = /** */ 0b000000100000;
|
||||||
export const Snapshot = 'Snapshot';
|
export const Snapshot = /** */ 0b000000010000;
|
||||||
// 被中断了,抛出错误的vNode以及它的父vNode
|
export const Interrupted = /** */ 0b000000001000; // 被中断了,抛出错误的vNode以及它的父vNode
|
||||||
export const Interrupted = 'Interrupted';
|
export const ShouldCapture =/** */ 0b000000000100;
|
||||||
export const ShouldCapture = 'ShouldCapture';
|
export const ForceUpdate = /** */ 0b000000000010; // For suspense
|
||||||
// For suspense
|
export const Clear = /** */ 0b000000000001;
|
||||||
export const ForceUpdate = 'ForceUpdate';
|
const LifecycleEffectArr = Update | Callback | Ref | Snapshot;
|
||||||
export const Clear = 'Clear';
|
|
||||||
|
|
||||||
const FlagArr = [Addition, Update, Deletion, Clear, ResetText, Callback,
|
|
||||||
DidCapture, Ref, Snapshot, Interrupted, ShouldCapture, ForceUpdate];
|
|
||||||
|
|
||||||
const LifecycleEffectArr = [Update, Callback, Ref, Snapshot];
|
|
||||||
|
|
||||||
function resetFlag(node) {
|
|
||||||
node.flags = {};
|
|
||||||
}
|
|
||||||
|
|
||||||
export class FlagUtils {
|
export class FlagUtils {
|
||||||
static removeFlag(node: VNode, flag: string) {
|
static removeFlag(node: VNode, flag: number) {
|
||||||
node.flags[flag] = false;
|
const flags = node.flags;
|
||||||
|
node.flags = flags & (~flag);
|
||||||
}
|
}
|
||||||
static removeLifecycleEffectFlags(node) {
|
static removeLifecycleEffectFlags(node) {
|
||||||
LifecycleEffectArr.forEach(key => {
|
const flags = node.flags;
|
||||||
node.flags[key] = false;
|
node.flags = flags & (~LifecycleEffectArr);
|
||||||
});
|
|
||||||
}
|
}
|
||||||
static hasAnyFlag(node: VNode) { // 有标志位
|
static hasAnyFlag(node: VNode) { // 有标志位
|
||||||
const flags = node.flags;
|
return node.flags !== InitFlag;
|
||||||
const arrLength = FlagArr.length;
|
|
||||||
let key;
|
|
||||||
for (let i = 0; i < arrLength; i++) {
|
|
||||||
key = FlagArr[i];
|
|
||||||
if (flags[key]) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static setNoFlags(node: VNode) {
|
static setNoFlags(node: VNode) {
|
||||||
resetFlag(node);
|
node.flags = InitFlag;
|
||||||
}
|
}
|
||||||
|
|
||||||
static markAddition(node: VNode) {
|
static markAddition(node: VNode) {
|
||||||
node.flags.Addition = true;
|
node.flags |= Addition;
|
||||||
}
|
}
|
||||||
static setAddition(node: VNode) {
|
static setAddition(node: VNode) {
|
||||||
resetFlag(node);
|
node.flags = Addition;
|
||||||
node.flags.Addition = true;
|
|
||||||
}
|
}
|
||||||
static markUpdate(node: VNode) {
|
static markUpdate(node: VNode) {
|
||||||
node.flags.Update = true;
|
node.flags |= Update;
|
||||||
}
|
}
|
||||||
static setDeletion(node: VNode) {
|
static setDeletion(node: VNode) {
|
||||||
resetFlag(node);
|
node.flags = Deletion;
|
||||||
node.flags.Deletion = true;
|
|
||||||
}
|
}
|
||||||
static markContentReset(node: VNode) {
|
static markContentReset(node: VNode) {
|
||||||
node.flags.ResetText = true;
|
node.flags |= ResetText;
|
||||||
}
|
}
|
||||||
static markCallback(node: VNode) {
|
static markCallback(node: VNode) {
|
||||||
node.flags.Callback = true;
|
node.flags |= Callback;
|
||||||
}
|
}
|
||||||
static markDidCapture(node: VNode) {
|
static markDidCapture(node: VNode) {
|
||||||
node.flags.DidCapture = true;
|
node.flags |= DidCapture;
|
||||||
}
|
}
|
||||||
static markShouldCapture(node: VNode) {
|
static markShouldCapture(node: VNode) {
|
||||||
node.flags.ShouldCapture = true;
|
node.flags |= ShouldCapture;
|
||||||
}
|
}
|
||||||
static markRef(node: VNode) {
|
static markRef(node: VNode) {
|
||||||
node.flags.Ref = true;
|
node.flags |= Ref;
|
||||||
}
|
}
|
||||||
static markSnapshot(node: VNode) {
|
static markSnapshot(node: VNode) {
|
||||||
node.flags.Snapshot = true;
|
node.flags |= Snapshot;
|
||||||
}
|
}
|
||||||
static markInterrupted(node: VNode) {
|
static markInterrupted(node: VNode) {
|
||||||
node.flags.Interrupted = true;
|
node.flags |= Interrupted;
|
||||||
}
|
}
|
||||||
static markForceUpdate(node: VNode) {
|
static markForceUpdate(node: VNode) {
|
||||||
node.flags.ForceUpdate = true;
|
node.flags |= ForceUpdate;
|
||||||
}
|
}
|
||||||
|
|
||||||
static markClear(node: VNode) {
|
static markClear(node: VNode) {
|
||||||
node.flags.Clear = true;
|
node.flags |= Clear;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,10 +7,7 @@ import type {VNode} from '../Types';
|
||||||
import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags';
|
import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags';
|
||||||
import {isComment} from '../../dom/utils/Common';
|
import {isComment} from '../../dom/utils/Common';
|
||||||
import {getNearestVNode} from '../../dom/DOMInternalKeys';
|
import {getNearestVNode} from '../../dom/DOMInternalKeys';
|
||||||
|
import { Addition, InitFlag } from './VNodeFlags';
|
||||||
export function getSiblingVNode(node) {
|
|
||||||
return node.next;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) {
|
export function travelChildren(beginVNode: VNode, handleVNode: Function, isFinish?: Function) {
|
||||||
let node: VNode | null = beginVNode;
|
let node: VNode | null = beginVNode;
|
||||||
|
@ -58,7 +55,7 @@ export function travelVNodeTree(
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找兄弟,没有就往上再找兄弟
|
// 找兄弟,没有就往上再找兄弟
|
||||||
while (getSiblingVNode(node) === null) {
|
while (node.next === null) {
|
||||||
if (node.parent === null || node.parent === overVNode) {
|
if (node.parent === null || node.parent === overVNode) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -69,7 +66,7 @@ export function travelVNodeTree(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// 找到兄弟
|
// 找到兄弟
|
||||||
const siblingVNode = getSiblingVNode(node);
|
const siblingVNode = node.next;
|
||||||
siblingVNode.parent = node.parent;
|
siblingVNode.parent = node.parent;
|
||||||
node = siblingVNode;
|
node = siblingVNode;
|
||||||
}
|
}
|
||||||
|
@ -96,6 +93,7 @@ export function clearVNode(vNode: VNode) {
|
||||||
vNode.oldState = null;
|
vNode.oldState = null;
|
||||||
vNode.oldRef = null;
|
vNode.oldRef = null;
|
||||||
vNode.oldChild = null;
|
vNode.oldChild = null;
|
||||||
|
vNode.flags = InitFlag;
|
||||||
|
|
||||||
vNode.toUpdateNodes = null;
|
vNode.toUpdateNodes = null;
|
||||||
|
|
||||||
|
@ -175,7 +173,7 @@ export function getSiblingDom(vNode: VNode): Element | null {
|
||||||
|
|
||||||
findSibling: while (true) {
|
findSibling: while (true) {
|
||||||
// 没有兄弟节点,找父节点
|
// 没有兄弟节点,找父节点
|
||||||
while (getSiblingVNode(node) === null) {
|
while (node.next === null) {
|
||||||
// 没父节点,或父节点已经是根节点,则返回
|
// 没父节点,或父节点已经是根节点,则返回
|
||||||
if (node.parent === null || isDomContainer(node.parent)) {
|
if (node.parent === null || isDomContainer(node.parent)) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -183,14 +181,14 @@ export function getSiblingDom(vNode: VNode): Element | null {
|
||||||
node = node.parent;
|
node = node.parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
const siblingVNode = getSiblingVNode(node);
|
const siblingVNode = node.next;
|
||||||
siblingVNode.parent = node.parent;
|
siblingVNode.parent = node.parent;
|
||||||
node = siblingVNode;
|
node = siblingVNode;
|
||||||
|
|
||||||
// 如果不是dom节点,往下找
|
// 如果不是dom节点,往下找
|
||||||
while (!isDomVNode(node)) {
|
while (!isDomVNode(node)) {
|
||||||
// 如果节点也是Addition
|
// 如果节点也是Addition
|
||||||
if (node.flags.Addition) {
|
if ((node.flags & Addition) ===Addition) {
|
||||||
continue findSibling;
|
continue findSibling;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -204,7 +202,7 @@ export function getSiblingDom(vNode: VNode): Element | null {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node.flags.Addition) {
|
if ((node.flags & Addition) ===InitFlag) {
|
||||||
// 找到
|
// 找到
|
||||||
return node.realNode;
|
return node.realNode;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue