Match-id-4fda5cb9bbe9df287d64c784b13b9071368c157a

This commit is contained in:
* 2022-01-26 17:10:59 +08:00 committed by *
parent 12b653252f
commit 89f26b7e14
16 changed files with 177 additions and 181 deletions

View File

@ -1,3 +1,14 @@
function isNeedUnitCSS(propName: string) {
return !(noUnitCSS.includes(propName)
|| propName.startsWith('borderImage')
|| propName.startsWith('flex')
|| propName.startsWith('gridRow')
|| propName.startsWith('gridColumn')
|| propName.startsWith('stroke')
|| propName.startsWith('box')
|| propName.endsWith('Opacity'));
}
/** /**
* width: 10 => width: 10px * width: 10 => width: 10px
* *
@ -38,14 +49,3 @@ export function setStyles(dom, styles) {
*/ */
const noUnitCSS = ['animationIterationCount', 'columnCount', 'columns', 'gridArea', 'fontWeight', 'lineClamp', const noUnitCSS = ['animationIterationCount', 'columnCount', 'columns', 'gridArea', 'fontWeight', 'lineClamp',
'lineHeight', 'opacity', 'order', 'orphans', 'tabSize', 'widows', 'zIndex', 'zoom']; 'lineHeight', 'opacity', 'order', 'orphans', 'tabSize', 'widows', 'zIndex', 'zoom'];
function isNeedUnitCSS(propName: string) {
return !(noUnitCSS.includes(propName)
|| propName.startsWith('borderImage')
|| propName.startsWith('flex')
|| propName.startsWith('gridRow')
|| propName.startsWith('gridColumn')
|| propName.startsWith('stroke')
|| propName.startsWith('box')
|| propName.endsWith('Opacity'));
}

View File

@ -21,7 +21,6 @@ const svgHumpAttr = new Set(['allowReorder', 'autoReverse', 'baseFrequency', 'ba
// 驼峰 变 “-” // 驼峰 变 “-”
function convertToLowerCase(str) { function convertToLowerCase(str) {
const replacer = (match, char) => `-${char.toLowerCase()}`; const replacer = (match, char) => `-${char.toLowerCase()}`;
return str.replace(/([A-Z])/g, replacer); return str.replace(/([A-Z])/g, replacer);
} }

View File

@ -107,9 +107,9 @@ export function getSelectionInfo() {
export interface SelectionData { export interface SelectionData {
focusedDom: HTMLInputElement | HTMLTextAreaElement | void; focusedDom: HTMLInputElement | HTMLTextAreaElement | void;
selectionRange: { selectionRange?: {
start: number | null; start: number;
end: number | null; end: number;
}; };
} }

View File

@ -3,7 +3,7 @@ export interface IProperty {
} }
export interface HorizonSelect extends HTMLSelectElement { export interface HorizonSelect extends HTMLSelectElement {
_multiple: boolean; _multiple?: boolean;
} }
export type HorizonDom = Element | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement; export type HorizonDom = Element | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;

View File

@ -12,6 +12,44 @@ function getItemKey(item: any, index: number): string {
return '.' + index.toString(36); return '.' + index.toString(36);
} }
function mapChildrenToArray(
children: any,
arr: Array<any>,
prefix: string,
callback?: Function,
): number | void {
const type = typeof children;
switch (type) {
// 继承原有规格undefined和boolean类型按照null处理
case 'undefined':
case 'boolean':
callMapFun(null, arr, prefix, callback);
return;
case 'number':
case 'string':
callMapFun(children, arr, prefix, callback);
return;
case 'object':
if (children === null) {
callMapFun(null, arr, prefix, callback);
return;
}
const vtype = children.vtype;
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
callMapFun(children, arr, prefix, callback) ;
return;
}
if (Array.isArray(children)) {
processArrayChildren(children, arr, prefix, callback);
return;
}
throw new Error(
'Object is invalid as a Horizon child. '
);
// No Default
}
}
function processArrayChildren( function processArrayChildren(
children: any, children: any,
arr: Array<any>, arr: Array<any>,
@ -61,44 +99,6 @@ function callMapFun(
} }
} }
function mapChildrenToArray(
children: any,
arr: Array<any>,
prefix: string,
callback?: Function,
): number | void {
const type = typeof children;
switch (type) {
// 继承原有规格undefined和boolean类型按照null处理
case 'undefined':
case 'boolean':
callMapFun(null, arr, prefix, callback);
return;
case 'number':
case 'string':
callMapFun(children, arr, prefix, callback);
return;
case 'object':
if (children === null) {
callMapFun(null, arr, prefix, callback);
return;
}
const vtype = children.vtype;
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
callMapFun(children, arr, prefix, callback) ;
return;
}
if (Array.isArray(children)) {
processArrayChildren(children, arr, prefix, callback);
return;
}
throw new Error(
'Object is invalid as a Horizon child. '
);
// No Default
}
}
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg // 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
function mapChildren( function mapChildren(
children: any, children: any,

View File

@ -41,7 +41,7 @@ function buildElement(isClone, type, setting, ...children) {
// setting中的值优先级最高clone情况下从 type 中取值,创建情况下直接赋值为 null // setting中的值优先级最高clone情况下从 type 中取值,创建情况下直接赋值为 null
const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null); const key = (setting && setting.key !== undefined) ? String(setting.key) : (isClone ? type.key : null);
const ref = (setting && setting.ref !== undefined) ? setting.ref : (isClone ? type.ref : null); const ref = (setting && setting.ref !== undefined) ? setting.ref : (isClone ? type.ref : null);
const props = isClone ? {...type.props} : {}; const props = isClone ? { ...type.props } : {};
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode(); let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
if (setting != null) { if (setting != null) {

View File

@ -13,6 +13,55 @@ import {setRootThrowError} from './submit/Submit';
import {handleSuspenseChildThrowError} from './render/SuspenseComponent'; import {handleSuspenseChildThrowError} from './render/SuspenseComponent';
import {updateShouldUpdateOfTree} from './vnode/VNodeShouldUpdate'; import {updateShouldUpdateOfTree} from './vnode/VNodeShouldUpdate';
function consoleError(error: any): void {
if (isDev) {
// 只打印message为了让测试用例能pass
console['error']('The codes throw the error: ' + error.message);
} else {
console['error'](error);
}
}
function handleRootError(
error: any,
) {
// 注意:如果根节点抛出错误,不会销毁整棵树,只打印日志,抛出异常。
setRootThrowError(error);
consoleError(error);
}
function createClassErrorUpdate(
vNode: VNode,
error: any,
): Update {
const update = newUpdate();
update.type = UpdateState.Error;
const getDerivedStateFromError = vNode.type.getDerivedStateFromError;
if (typeof getDerivedStateFromError === 'function') {
update.content = () => {
consoleError(error);
return getDerivedStateFromError(error);
};
}
const inst = vNode.realNode;
if (inst !== null && typeof inst.componentDidCatch === 'function') {
update.callback = function callback() {
if (typeof getDerivedStateFromError !== 'function') {
// 打印错误
consoleError(error);
}
// @ts-ignore
this.componentDidCatch(error, {
componentStack: '',
});
};
}
return update;
}
// 处理capture和bubble阶段抛出的错误 // 处理capture和bubble阶段抛出的错误
export function handleRenderThrowError( export function handleRenderThrowError(
sourceVNode: VNode, sourceVNode: VNode,
@ -76,6 +125,19 @@ export function handleRenderThrowError(
} while (vNode !== null); } while (vNode !== null);
} }
// 新增一个update并且触发调度
function triggerUpdate(vNode, state) {
const update = newUpdate();
update.content = state;
pushUpdate(vNode, update);
const root = updateShouldUpdateOfTree(vNode);
if (root !== null) {
tryRenderRoot(root);
}
}
// 处理submit阶段的异常 // 处理submit阶段的异常
export function handleSubmitError(vNode: VNode, error: any) { export function handleSubmitError(vNode: VNode, error: any) {
if (vNode.tag === TreeRoot) { if (vNode.tag === TreeRoot) {
@ -126,64 +188,3 @@ export function handleSubmitError(vNode: VNode, error: any) {
node = node.parent; node = node.parent;
} }
} }
function createClassErrorUpdate(
vNode: VNode,
error: any,
): Update {
const update = newUpdate();
update.type = UpdateState.Error;
const getDerivedStateFromError = vNode.type.getDerivedStateFromError;
if (typeof getDerivedStateFromError === 'function') {
update.content = () => {
consoleError(error);
return getDerivedStateFromError(error);
};
}
const inst = vNode.realNode;
if (inst !== null && typeof inst.componentDidCatch === 'function') {
update.callback = function callback() {
if (typeof getDerivedStateFromError !== 'function') {
// 打印错误
consoleError(error);
}
// @ts-ignore
this.componentDidCatch(error, {
componentStack: '',
});
};
}
return update;
}
// 新增一个update并且触发调度
function triggerUpdate(vNode, state) {
const update = newUpdate();
update.content = state;
pushUpdate(vNode, update);
const root = updateShouldUpdateOfTree(vNode);
if (root !== null) {
tryRenderRoot(root);
}
}
function handleRootError(
error: any,
) {
// 注意:如果根节点抛出错误,不会销毁整棵树,只打印日志,抛出异常。
setRootThrowError(error);
consoleError(error);
}
function consoleError(error: any): void {
if (isDev) {
// 只打印message为了让测试用例能pass
console['error']('The codes throw the error: ' + error.message);
} else {
console['error'](error);
}
}

View File

@ -129,6 +129,27 @@ function handleError(root, error): void {
bubbleVNode(processing); bubbleVNode(processing);
} }
// 判断数组中节点的path的idx元素是否都相等
function isEqualByIndex(idx: number, nodes: Array<VNode>) {
let val = nodes[0].path[idx];
for (let i = 1; i < nodes.length; i++) {
let node = nodes[i];
if (val !== node.path[idx]) {
return false;
}
}
return true;
}
function getChildByIndex(vNode: VNode, idx: number) {
let node = vNode.child;
for (let i = 0; i < idx; i++) {
node = node.next;
}
return node;
}
// 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点 // 从多个更新节点中,计算出开始节点。即:找到最近的共同的父辈节点
export function calcStartUpdateVNode(treeRoot: VNode) { export function calcStartUpdateVNode(treeRoot: VNode) {
const toUpdateNodes = Array.from(treeRoot.toUpdateNodes); const toUpdateNodes = Array.from(treeRoot.toUpdateNodes);
@ -292,27 +313,6 @@ export function launchUpdateFromVNode(vNode: VNode) {
} }
} }
// 判断数组中节点的path的idx元素是否都相等
function isEqualByIndex(idx: number, nodes: Array<VNode>) {
let val = nodes[0].path[idx];
for (let i = 1; i < nodes.length; i++) {
let node = nodes[i];
if (val !== node.path[idx]) {
return false;
}
}
return true;
}
function getChildByIndex(vNode: VNode, idx: number) {
let node = vNode.child;
for (let i = 0; i < idx; i++) {
node = node.next;
}
return node;
}
export function setBuildResultError() { export function setBuildResultError() {
if (getBuildResult() !== BuildCompleted) { if (getBuildResult() !== BuildCompleted) {
setBuildResult(BuildErrored); setBuildResult(BuildErrored);

View File

@ -2,9 +2,8 @@ import type { VNode, JSXElement } from '../Types';
// 当前vNode和element是同样的类型 // 当前vNode和element是同样的类型
// LazyComponent 会修改type的类型所以特殊处理这种类型 // LazyComponent 会修改type的类型所以特殊处理这种类型
export const isSameType = (vNode: VNode, ele: JSXElement) => { export const isSameType = (vNode: VNode, ele: JSXElement) =>
return vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type); vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type);
};
export function isTextType(newChild: any) { export function isTextType(newChild: any) {
return typeof newChild === 'string' || typeof newChild === 'number'; return typeof newChild === 'string' || typeof newChild === 'number';

View File

@ -17,7 +17,7 @@ enum DiffCategory {
TEXT_NODE = 'TEXT_NODE', TEXT_NODE = 'TEXT_NODE',
OBJECT_NODE = 'OBJECT_NODE', OBJECT_NODE = 'OBJECT_NODE',
ARR_NODE = 'ARR_NODE', ARR_NODE = 'ARR_NODE',
}; }
// 检查是不是被 FRAGMENT 包裹 // 检查是不是被 FRAGMENT 包裹
function isNoKeyFragment(child: any) { function isNoKeyFragment(child: any) {
@ -31,7 +31,7 @@ function deleteVNode(parentNode: VNode, delVNode: VNode): void {
} }
// 清除多个节点 // 清除多个节点
function deleteVNodes(parentVNode: VNode, startDelVNode: VNode, endVNode?: VNode): void { function deleteVNodes(parentVNode: VNode, startDelVNode: VNode | null, endVNode?: VNode): void {
let node = startDelVNode; let node = startDelVNode;
while (node !== null) { while (node !== null) {
@ -67,7 +67,7 @@ function checkCanReuseNode(oldNode: VNode | null, newChild: any): boolean {
return false; return false;
} }
function getNodeType(newChild: any): string { function getNodeType(newChild: any): string | null {
if (newChild === null) { if (newChild === null) {
return null; return null;
} }
@ -186,9 +186,7 @@ function transLeftChildrenToMap(
travelChildren(startChild, (node) => { travelChildren(startChild, (node) => {
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node); leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
}, (node) => { }, node => node === rightEndVNode);
return node === rightEndVNode;
});
return leftChildrenMap; return leftChildrenMap;
} }
@ -208,6 +206,11 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
return null; return null;
} }
function setCIndex(vNode: VNode, idx: number) {
vNode.cIndex = idx;
updateVNodePath(vNode);
}
// diff数组类型的节点核心算法 // diff数组类型的节点核心算法
function diffArrayNodes( function diffArrayNodes(
parentNode: VNode, parentNode: VNode,
@ -277,7 +280,7 @@ function diffArrayNodes(
// 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始 // 从后往前新资源的位置还没有到最末端旧的vNode也还没遍历完则可以考虑从后往前开始
if (rightIdx > leftIdx && oldNode !== null) { if (rightIdx > leftIdx && oldNode !== null) {
const rightRemainingOldChildren = transRightChildrenToArray(oldNode); const rightRemainingOldChildren = transRightChildrenToArray(oldNode);
let rightOldIndex = rightRemainingOldChildren.length - 1; let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
// 2. 从右侧开始比对currentVNode和newChildren若不能复用则跳出循环 // 2. 从右侧开始比对currentVNode和newChildren若不能复用则跳出循环
for (; rightIdx > leftIdx; rightIdx--) { for (; rightIdx > leftIdx; rightIdx--) {
@ -377,7 +380,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 = eIndexes[result[result.length - 1]]; const last: number | undefined = 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);
@ -455,11 +458,6 @@ function setVNodesCIndex(startChild: VNode, startIdx: number) {
} }
} }
function setCIndex(vNode: VNode, idx: number) {
vNode.cIndex = idx;
updateVNodePath(vNode);
}
// 新节点是数组类型 // 新节点是数组类型
function diffArrayNodesHandler( function diffArrayNodesHandler(
parentNode: VNode, parentNode: VNode,

View File

@ -14,7 +14,7 @@ import { getHookStage, HookStage } from './HookStage';
import type { VNode } from '../Types'; import type { VNode } from '../Types';
export function useReducerImpl<S, P, A>(reducer: (S, A) => export function useReducerImpl<S, P, A>(reducer: (S, A) =>
S, initArg: P, init?: (P) => S, isUseState?: boolean): [S, Trigger<A>] { S, initArg: P, init?: (P) => S, isUseState?: boolean): [S, Trigger<A>] | void {
const stage = getHookStage(); const stage = getHookStage();
if (stage === null) { if (stage === null) {
throwNotInFuncError(); throwNotInFuncError();

View File

@ -1,10 +1,6 @@
import type {VNode} from '../Types'; import type {VNode} from '../Types';
import {createVNodeChildren} from './BaseComponent'; import {createVNodeChildren} from './BaseComponent';
export function captureRender(processing: VNode): VNode | null {
return captureFragment(processing);
}
export function bubbleRender() {} export function bubbleRender() {}
function captureFragment(processing: VNode) { function captureFragment(processing: VNode) {
@ -12,3 +8,7 @@ function captureFragment(processing: VNode) {
processing.child = createVNodeChildren(processing, newElement); processing.child = createVNodeChildren(processing, newElement);
return processing.child; return processing.child;
} }
export function captureRender(processing: VNode): VNode | null {
return captureFragment(processing);
}

View File

@ -10,10 +10,6 @@ import {
} from '../../external/JSXElementType'; } from '../../external/JSXElementType';
import {Fragment} from '../vnode/VNodeTags'; import {Fragment} from '../vnode/VNodeTags';
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
return captureMemoComponent(processing, shouldUpdate);
}
export function bubbleRender() {} export function bubbleRender() {}
export function captureMemoComponent( export function captureMemoComponent(
@ -59,3 +55,7 @@ export function captureMemoComponent(
return newChild; return newChild;
} }
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
return captureMemoComponent(processing, shouldUpdate);
}

View File

@ -225,10 +225,10 @@ function unmountVNode(vNode: VNode): void {
function unmountNestedVNodes(vNode: VNode): void { function unmountNestedVNodes(vNode: VNode): void {
travelVNodeTree(vNode, (node) => { travelVNodeTree(vNode, (node) => {
unmountVNode(node); unmountVNode(node);
}, (node) => { }, node =>
// 如果是DomPortal不需要遍历child // 如果是DomPortal不需要遍历child
return node.tag === DomPortal; node.tag === DomPortal
}); );
} }
function submitAddition(vNode: VNode): void { function submitAddition(vNode: VNode): void {
@ -296,10 +296,9 @@ function unmountDomComponents(vNode: VNode): void {
} else { } else {
unmountVNode(node); unmountVNode(node);
} }
}, (node) => { }, node =>
// 如果是dom不用再遍历child // 如果是dom不用再遍历child
return node.tag === DomComponent || node.tag === DomText; node.tag === DomComponent || node.tag === DomText, null, (node) => {
}, null, (node) => {
if (node.tag === DomPortal) { if (node.tag === DomPortal) {
// 当离开portal需要重新设置parent // 当离开portal需要重新设置parent
currentParentIsValid = false; currentParentIsValid = false;

View File

@ -12,6 +12,16 @@ let callingQueueTask: any | null = null;
// 防止重入 // 防止重入
let isCallingRenderQueue = false; let isCallingRenderQueue = false;
export function callRenderQueueImmediate() {
if (callingQueueTask !== null) {
// 取消异步调度
cancelTask(callingQueueTask);
callingQueueTask = null;
}
callRenderQueue();
}
// 执行render回调 // 执行render回调
function callRenderQueue() { function callRenderQueue() {
if (!isCallingRenderQueue && renderQueue !== null) { if (!isCallingRenderQueue && renderQueue !== null) {
@ -54,13 +64,3 @@ export function pushRenderCallback(callback: RenderCallback) {
// 返回一个空对象用于区别null // 返回一个空对象用于区别null
return {}; return {};
} }
export function callRenderQueueImmediate() {
if (callingQueueTask !== null) {
// 取消异步调度
cancelTask(callingQueueTask);
callingQueueTask = null;
}
callRenderQueue();
}

View File

@ -42,9 +42,9 @@ export function shallowCompare(paramX: any, paramY: any): boolean {
return false; return false;
} }
return keysX.every((key, i) => { return keysX.every((key, i) =>
return Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]]); Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]])
}); );
} }
return false; return false;