Match-id-2d91c24f6bf9a30f69fafb1226cf060e0450d0cd
This commit is contained in:
commit
7d3f7c35e3
|
@ -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
|
||||
* 对空值或布尔值进行适配,转为空字符串
|
||||
|
@ -38,14 +49,3 @@ export function setStyles(dom, styles) {
|
|||
*/
|
||||
const noUnitCSS = ['animationIterationCount', 'columnCount', 'columns', 'gridArea', 'fontWeight', 'lineClamp',
|
||||
'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'));
|
||||
}
|
||||
|
|
|
@ -21,7 +21,6 @@ const svgHumpAttr = new Set(['allowReorder', 'autoReverse', 'baseFrequency', 'ba
|
|||
// 驼峰 变 “-”
|
||||
function convertToLowerCase(str) {
|
||||
const replacer = (match, char) => `-${char.toLowerCase()}`;
|
||||
|
||||
return str.replace(/([A-Z])/g, replacer);
|
||||
}
|
||||
|
||||
|
|
|
@ -107,9 +107,9 @@ export function getSelectionInfo() {
|
|||
|
||||
export interface SelectionData {
|
||||
focusedDom: HTMLInputElement | HTMLTextAreaElement | void;
|
||||
selectionRange: {
|
||||
start: number | null;
|
||||
end: number | null;
|
||||
selectionRange?: {
|
||||
start: number;
|
||||
end: number;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ export interface IProperty {
|
|||
}
|
||||
|
||||
export interface HorizonSelect extends HTMLSelectElement {
|
||||
_multiple: boolean;
|
||||
_multiple?: boolean;
|
||||
}
|
||||
|
||||
export type HorizonDom = Element | HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;
|
||||
|
|
|
@ -12,6 +12,44 @@ function getItemKey(item: any, index: number): string {
|
|||
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(
|
||||
children: 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
|
||||
function mapChildren(
|
||||
children: any,
|
||||
|
|
|
@ -41,7 +41,7 @@ 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 props = isClone ? {...type.props} : {};
|
||||
const props = isClone ? { ...type.props } : {};
|
||||
let vNode = isClone ? type.belongClassVNode : getProcessingClassVNode();
|
||||
|
||||
if (setting != null) {
|
||||
|
|
|
@ -13,6 +13,55 @@ import {setRootThrowError} from './submit/Submit';
|
|||
import {handleSuspenseChildThrowError} from './render/SuspenseComponent';
|
||||
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阶段抛出的错误
|
||||
export function handleRenderThrowError(
|
||||
sourceVNode: VNode,
|
||||
|
@ -76,6 +125,19 @@ export function handleRenderThrowError(
|
|||
} 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阶段的异常
|
||||
export function handleSubmitError(vNode: VNode, error: any) {
|
||||
if (vNode.tag === TreeRoot) {
|
||||
|
@ -126,64 +188,3 @@ export function handleSubmitError(vNode: VNode, error: any) {
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -129,6 +129,27 @@ function handleError(root, error): void {
|
|||
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) {
|
||||
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() {
|
||||
if (getBuildResult() !== BuildCompleted) {
|
||||
setBuildResult(BuildErrored);
|
||||
|
|
|
@ -2,9 +2,8 @@ import type { VNode, JSXElement } from '../Types';
|
|||
|
||||
// 当前vNode和element是同样的类型
|
||||
// LazyComponent 会修改type的类型,所以特殊处理这种类型
|
||||
export const isSameType = (vNode: VNode, ele: JSXElement) => {
|
||||
return vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type);
|
||||
};
|
||||
export const isSameType = (vNode: VNode, ele: JSXElement) =>
|
||||
vNode.type === ele.type || (vNode.isLazyComponent && vNode.lazyType === ele.type);
|
||||
|
||||
export function isTextType(newChild: any) {
|
||||
return typeof newChild === 'string' || typeof newChild === 'number';
|
||||
|
|
|
@ -17,7 +17,7 @@ enum DiffCategory {
|
|||
TEXT_NODE = 'TEXT_NODE',
|
||||
OBJECT_NODE = 'OBJECT_NODE',
|
||||
ARR_NODE = 'ARR_NODE',
|
||||
};
|
||||
}
|
||||
|
||||
// 检查是不是被 FRAGMENT 包裹
|
||||
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;
|
||||
|
||||
while (node !== null) {
|
||||
|
@ -67,7 +67,7 @@ function checkCanReuseNode(oldNode: VNode | null, newChild: any): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
function getNodeType(newChild: any): string {
|
||||
function getNodeType(newChild: any): string | null {
|
||||
if (newChild === null) {
|
||||
return null;
|
||||
}
|
||||
|
@ -186,9 +186,7 @@ function transLeftChildrenToMap(
|
|||
|
||||
travelChildren(startChild, (node) => {
|
||||
leftChildrenMap.set(node.key !== null ? node.key : node.eIndex, node);
|
||||
}, (node) => {
|
||||
return node === rightEndVNode;
|
||||
});
|
||||
}, node => node === rightEndVNode);
|
||||
|
||||
return leftChildrenMap;
|
||||
}
|
||||
|
@ -208,6 +206,11 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
|||
return null;
|
||||
}
|
||||
|
||||
function setCIndex(vNode: VNode, idx: number) {
|
||||
vNode.cIndex = idx;
|
||||
updateVNodePath(vNode);
|
||||
}
|
||||
|
||||
// diff数组类型的节点,核心算法
|
||||
function diffArrayNodes(
|
||||
parentNode: VNode,
|
||||
|
@ -277,7 +280,7 @@ function diffArrayNodes(
|
|||
// 从后往前,新资源的位置还没有到最末端,旧的vNode也还没遍历完,则可以考虑从后往前开始
|
||||
if (rightIdx > leftIdx && oldNode !== null) {
|
||||
const rightRemainingOldChildren = transRightChildrenToArray(oldNode);
|
||||
let rightOldIndex = rightRemainingOldChildren.length - 1;
|
||||
let rightOldIndex: number | null = rightRemainingOldChildren.length - 1;
|
||||
|
||||
// 2. 从右侧开始比对currentVNode和newChildren,若不能复用则跳出循环
|
||||
for (; rightIdx > leftIdx; rightIdx--) {
|
||||
|
@ -377,7 +380,7 @@ function diffArrayNodes(
|
|||
if (oldNodeFromMap !== null) {
|
||||
let eIndex = newNode.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直接放在最后
|
||||
preIndex[i] = result[result.length - 1];
|
||||
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(
|
||||
parentNode: VNode,
|
||||
|
|
|
@ -14,7 +14,7 @@ import { getHookStage, HookStage } from './HookStage';
|
|||
import type { VNode } from '../Types';
|
||||
|
||||
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();
|
||||
if (stage === null) {
|
||||
throwNotInFuncError();
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
import type {VNode} from '../Types';
|
||||
import {createVNodeChildren} from './BaseComponent';
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return captureFragment(processing);
|
||||
}
|
||||
|
||||
export function bubbleRender() {}
|
||||
|
||||
function captureFragment(processing: VNode) {
|
||||
|
@ -12,3 +8,7 @@ function captureFragment(processing: VNode) {
|
|||
processing.child = createVNodeChildren(processing, newElement);
|
||||
return processing.child;
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode): VNode | null {
|
||||
return captureFragment(processing);
|
||||
}
|
||||
|
|
|
@ -10,10 +10,6 @@ import {
|
|||
} from '../../external/JSXElementType';
|
||||
import {Fragment} from '../vnode/VNodeTags';
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||
return captureMemoComponent(processing, shouldUpdate);
|
||||
}
|
||||
|
||||
export function bubbleRender() {}
|
||||
|
||||
export function captureMemoComponent(
|
||||
|
@ -59,3 +55,7 @@ export function captureMemoComponent(
|
|||
|
||||
return newChild;
|
||||
}
|
||||
|
||||
export function captureRender(processing: VNode, shouldUpdate: boolean): VNode | null {
|
||||
return captureMemoComponent(processing, shouldUpdate);
|
||||
}
|
||||
|
|
|
@ -225,10 +225,10 @@ function unmountVNode(vNode: VNode): void {
|
|||
function unmountNestedVNodes(vNode: VNode): void {
|
||||
travelVNodeTree(vNode, (node) => {
|
||||
unmountVNode(node);
|
||||
}, (node) => {
|
||||
}, node =>
|
||||
// 如果是DomPortal,不需要遍历child
|
||||
return node.tag === DomPortal;
|
||||
});
|
||||
node.tag === DomPortal
|
||||
);
|
||||
}
|
||||
|
||||
function submitAddition(vNode: VNode): void {
|
||||
|
@ -296,10 +296,9 @@ function unmountDomComponents(vNode: VNode): void {
|
|||
} else {
|
||||
unmountVNode(node);
|
||||
}
|
||||
}, (node) => {
|
||||
}, node =>
|
||||
// 如果是dom不用再遍历child
|
||||
return node.tag === DomComponent || node.tag === DomText;
|
||||
}, null, (node) => {
|
||||
node.tag === DomComponent || node.tag === DomText, null, (node) => {
|
||||
if (node.tag === DomPortal) {
|
||||
// 当离开portal,需要重新设置parent
|
||||
currentParentIsValid = false;
|
||||
|
|
|
@ -12,6 +12,16 @@ let callingQueueTask: any | null = null;
|
|||
// 防止重入
|
||||
let isCallingRenderQueue = false;
|
||||
|
||||
export function callRenderQueueImmediate() {
|
||||
if (callingQueueTask !== null) {
|
||||
// 取消异步调度
|
||||
cancelTask(callingQueueTask);
|
||||
callingQueueTask = null;
|
||||
}
|
||||
|
||||
callRenderQueue();
|
||||
}
|
||||
|
||||
// 执行render回调
|
||||
function callRenderQueue() {
|
||||
if (!isCallingRenderQueue && renderQueue !== null) {
|
||||
|
@ -54,13 +64,3 @@ export function pushRenderCallback(callback: RenderCallback) {
|
|||
// 返回一个空对象,用于区别null
|
||||
return {};
|
||||
}
|
||||
|
||||
export function callRenderQueueImmediate() {
|
||||
if (callingQueueTask !== null) {
|
||||
// 取消异步调度
|
||||
cancelTask(callingQueueTask);
|
||||
callingQueueTask = null;
|
||||
}
|
||||
|
||||
callRenderQueue();
|
||||
}
|
||||
|
|
|
@ -42,9 +42,9 @@ export function shallowCompare(paramX: any, paramY: any): boolean {
|
|||
return false;
|
||||
}
|
||||
|
||||
return keysX.every((key, i) => {
|
||||
return Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]]);
|
||||
});
|
||||
return keysX.every((key, i) =>
|
||||
Object.prototype.hasOwnProperty.call(paramY, key) && isSame(paramX[key], paramY[keysX[i]])
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
Loading…
Reference in New Issue