Match-id-ad7c692603a33470196a2c41cdb3ff21136732d9

This commit is contained in:
* 2023-05-06 16:14:22 +08:00
parent a0e05e8f42
commit 3d42a535d6
11 changed files with 90 additions and 43 deletions

View File

@ -48,7 +48,7 @@ export function setDomProps(dom: Element, props: Object, isNativeTag: boolean, i
}
} else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html;
} else if (!isInit || (isInit && propVal != null)) {
} else if (!isInit || propVal != null) {
updateCommonProp(dom, propName, propVal, isNativeTag);
}
}
@ -70,7 +70,7 @@ export function compareProps(oldProps: Object, newProps: Object): Object {
for (let i = 0; i < oldPropsLength; i++) {
propName = keysOfOldProps[i];
// 新属性中包含该属性或者该属性为空值的属性不需要处理
if (keysOfNewProps.includes(propName) || oldProps[propName] == null) {
if ( oldProps[propName] == null || keysOfNewProps.includes(propName)) {
continue;
}

View File

@ -82,8 +82,7 @@ export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
}
if (!events[nativeFullName]) {
const listener = listenToNativeEvent(nativeEvent, currentRoot.realNode, isCapture);
events[nativeFullName] = listener;
events[nativeFullName] = listenToNativeEvent(nativeEvent, currentRoot.realNode, isCapture);
}
});
}

View File

@ -17,6 +17,7 @@ import { throwIfTrue } from '../renderer/utils/throwIfTrue';
import { TYPE_COMMON_ELEMENT, TYPE_PORTAL } from './JSXElementType';
import { isValidElement, JSXElement } from './JSXElement';
import { BELONG_CLASS_VNODE_KEY } from '../renderer/vnode/VNode';
// 生成key
function getItemKey(item: any, index: number): string {
@ -83,7 +84,7 @@ function callMapFun(children: any, arr: Array<any>, prefix: string, callback: Fu
mappedChild.type,
newKey,
mappedChild.ref,
mappedChild.belongClassVNode,
mappedChild[BELONG_CLASS_VNODE_KEY],
mappedChild.props,
mappedChild.src
);

View File

@ -16,6 +16,7 @@
import { TYPE_COMMON_ELEMENT } from './JSXElementType';
import { getProcessingClassVNode } from '../renderer/GlobalVar';
import { Source } from '../renderer/Types';
import { BELONG_CLASS_VNODE_KEY } from '../renderer/vnode/VNode';
/**
* vtype element
@ -36,17 +37,9 @@ export function JSXElement(type, key, ref, vNode, props, source: Source | null)
ref: ref,
props: props,
// 所属的class组件
belongClassVNode: null,
// 所属的class组件,clonedeep jsxElement时需要防止无限循环
[BELONG_CLASS_VNODE_KEY]: vNode,
};
// 在 cloneDeep JSXElement 的时候会出现死循环需要设置belongClassVNode的enumerable为false
Object.defineProperty(ele, 'belongClassVNode', {
configurable: false,
enumerable: false,
value: vNode,
});
if (isDev) {
// 为了test判断两个 JSXElement 对象是否相等时忽略src属性需要设置src的enumerable为false
Object.defineProperty(ele, 'src', {
@ -60,11 +53,6 @@ export function JSXElement(type, key, ref, vNode, props, source: Source | null)
return ele;
}
function isValidKey(key) {
const keyArray = ['key', 'ref', '__source', '__self'];
return !keyArray.includes(key);
}
function mergeDefault(sourceObj, defaultObj) {
Object.keys(defaultObj).forEach(key => {
if (sourceObj[key] === undefined) {
@ -73,19 +61,20 @@ function mergeDefault(sourceObj, defaultObj) {
});
}
// ['key', 'ref', '__source', '__self']属性不从setting获取
const keyArray = ['key', 'ref', '__source', '__self'];
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();
let vNode = isClone ? type[BELONG_CLASS_VNODE_KEY] : getProcessingClassVNode();
if (setting !== null && setting !== undefined) {
const keys = Object.keys(setting);
const keyLength = keys.length;
for (let i = 0; i < keyLength; i++) {
const k = keys[i];
if (isValidKey(k)) {
for (const k in setting) {
if (!keyArray.includes(k)) {
props[k] = setting[k];
}
}
@ -109,7 +98,6 @@ function buildElement(isClone, type, setting, children) {
lineNumber: setting.__source.lineNumber,
};
}
return JSXElement(element, key, ref, vNode, props, src);
}

View File

@ -15,15 +15,20 @@
import { VNode } from './vnode/VNode';
const currentRootStack: VNode[] = [];
const currentRootStack: (VNode | undefined)[] = [];
let index = -1;
export function getCurrentRoot() {
return currentRootStack[currentRootStack.length - 1];
return currentRootStack[index];
}
export function pushCurrentRoot(root: VNode) {
return currentRootStack.push(root);
index++;
currentRootStack[index] = root;
}
export function popCurrentRoot() {
return currentRootStack.pop();
const target = currentRootStack[index];
currentRootStack[index] = undefined;
index--;
return target;
}

View File

@ -13,6 +13,8 @@
* See the Mulan PSL v2 for more details.
*/
import { BELONG_CLASS_VNODE_KEY } from './vnode/VNode';
export { VNode } from './vnode/VNode';
type Trigger<A> = (A) => void;
@ -32,7 +34,7 @@ export type JSXElement = {
key: any;
ref: any;
props: any;
belongClassVNode: any;
[BELONG_CLASS_VNODE_KEY]: any;
};
export type ProviderType<T> = {

View File

@ -27,6 +27,7 @@ import {
import { isSameType, getIteratorFn, isTextType, isIteratorType, isObjectType } from './DiffTools';
import { travelChildren } from '../vnode/VNodeUtils';
import { markVNodePath } from '../utils/vNodePath';
import { BELONG_CLASS_VNODE_KEY } from '../vnode/VNode';
enum DiffCategory {
TEXT_NODE = 'TEXT_NODE',
@ -166,11 +167,11 @@ function getNewNode(parentNode: VNode, newChild: any, oldNode: VNode | null) {
if (oldNode === null || !isSameType(oldNode, newChild)) {
resultNode = createVNodeFromElement(newChild);
resultNode.ref = newChild.ref;
resultNode.belongClassVNode = newChild.belongClassVNode;
resultNode[BELONG_CLASS_VNODE_KEY] = newChild[BELONG_CLASS_VNODE_KEY];
} else {
resultNode = updateVNode(oldNode, newChild.props);
resultNode.ref = newChild.ref;
resultNode.belongClassVNode = newChild.belongClassVNode;
resultNode[BELONG_CLASS_VNODE_KEY] = newChild[BELONG_CLASS_VNODE_KEY];
}
break;
} else if (newChild.vtype === TYPE_PORTAL) {
@ -570,7 +571,7 @@ function diffObjectNodeHandler(
} else if (isSameType(canReuseNode, newChild)) {
resultNode = updateVNode(canReuseNode, newChild.props);
resultNode.ref = newChild.ref;
resultNode.belongClassVNode = newChild.belongClassVNode;
resultNode[BELONG_CLASS_VNODE_KEY] = newChild[BELONG_CLASS_VNODE_KEY];
startDelVNode = resultNode.next;
resultNode.next = null;
}
@ -583,7 +584,7 @@ function diffObjectNodeHandler(
} else {
resultNode = createVNodeFromElement(newChild);
resultNode.ref = newChild.ref;
resultNode.belongClassVNode = newChild.belongClassVNode;
resultNode[BELONG_CLASS_VNODE_KEY] = newChild[BELONG_CLASS_VNODE_KEY];
}
}
} else if (newChild.vtype === TYPE_PORTAL) {

View File

@ -52,6 +52,7 @@ import {
import { handleSubmitError } from '../ErrorHandler';
import { travelVNodeTree, clearVNode, isDomVNode, getSiblingDom } from '../vnode/VNodeUtils';
import { shouldAutoFocus } from '../../dom/utils/Common';
import { BELONG_CLASS_VNODE_KEY } from '../vnode/VNode';
function callComponentWillUnmount(vNode: VNode, instance: any) {
try {
@ -163,8 +164,8 @@ function handleRef(vNode: VNode, ref, val) {
} else if (refType === 'object') {
(<RefType>ref).current = val;
} else {
if (vNode.belongClassVNode && vNode.belongClassVNode.realNode) {
vNode.belongClassVNode.realNode.refs[String(ref)] = val;
if (vNode[BELONG_CLASS_VNODE_KEY] && vNode[BELONG_CLASS_VNODE_KEY].realNode) {
vNode[BELONG_CLASS_VNODE_KEY].realNode.refs[String(ref)] = val;
}
}
}

View File

@ -38,6 +38,8 @@ import type { Hook } from '../hooks/HookType';
import { InitFlag } from './VNodeFlags';
import { Observer } from '../../horizonx/proxy/Observer';
export const BELONG_CLASS_VNODE_KEY = Symbol('belongClassVNode');
export class VNode {
tag: VNodeTag;
key: string | null; // 唯一标识符
@ -97,7 +99,7 @@ export class VNode {
toUpdateNodes: Set<VNode> | null; // 保存要更新的节点
delegatedEvents: Set<string>;
belongClassVNode: VNode | null = null; // 记录JSXElement所属class vNode处理ref的时候使用
[BELONG_CLASS_VNODE_KEY]: VNode | null = null; // 记录JSXElement所属class vNode处理ref的时候使用
// 状态管理器HorizonX使用
isStoreChange: boolean;

View File

@ -20,9 +20,9 @@
import type {VNode} from '../Types';
import {DomComponent, DomPortal, DomText, TreeRoot} from './VNodeTags';
import {isComment} from '../../dom/utils/Common';
import {getNearestVNode} from '../../dom/DOMInternalKeys';
import {Addition, InitFlag} from './VNodeFlags';
import { BELONG_CLASS_VNODE_KEY } from './VNode';
export function travelChildren(
beginVNode: VNode | null,
@ -124,7 +124,7 @@ export function clearVNode(vNode: VNode) {
vNode.toUpdateNodes = null;
vNode.belongClassVNode = null;
vNode[BELONG_CLASS_VNODE_KEY] = null;
if (window.__HORIZON_DEV_HOOK__) {
const hook = window.__HORIZON_DEV_HOOK__;
hook.deleteVNode(vNode);

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2020 Huawei Technologies Co.,Ltd.
*
* openGauss is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*
* http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
* See the Mulan PSL v2 for more details.
*/
import * as Horizon from '@cloudsop/horizon/index.ts';
describe('JSX Element test', () => {
it('symbol attribute prevent cloneDeep unlimited loop', function () {
function cloneDeep(obj) {
const result = {};
Object.keys(obj).forEach(key => {
if (obj[key] && typeof obj[key] === 'object') {
result[key] = cloneDeep(obj[key]);
} else {
result[key] = obj[key];
}
})
return result;
}
class Demo extends Horizon.Component {
render() {
return (
<div>
hello
</div>
);
}
}
const ele = Horizon.createElement(Demo);
const copy = cloneDeep(ele);
expect(copy.vtype).toEqual(ele.vtype);
expect(Object.getOwnPropertySymbols(copy).length).toEqual(0);
});
});