Match-id-0d2ee97c73eb3c17b73cacb842949e5fb6877812

This commit is contained in:
* 2023-04-18 15:03:18 +08:00
commit e5f878bebf
13 changed files with 474 additions and 470 deletions

View File

@ -13,6 +13,26 @@
* See the Mulan PSL v2 for more details.
*/
/**
* css
*/
const noUnitCSS = [
'animationIterationCount',
'columnCount',
'columns',
'gridArea',
'fontWeight',
'lineClamp',
'lineHeight',
'opacity',
'order',
'orphans',
'tabSize',
'widows',
'zIndex',
'zoom',
];
function isNeedUnitCSS(styleName: string) {
return !(
noUnitCSS.includes(styleName) ||
@ -62,23 +82,3 @@ export function setStyles(dom, styles) {
}
});
}
/**
* css
*/
const noUnitCSS = [
'animationIterationCount',
'columnCount',
'columns',
'gridArea',
'fontWeight',
'lineClamp',
'lineHeight',
'opacity',
'order',
'orphans',
'tabSize',
'widows',
'zIndex',
'zoom',
];

View File

@ -56,6 +56,14 @@ function listenToNativeEvent(nativeEvtName: string, delegatedElement: Element, i
return listener;
}
// 是否捕获事件
function isCaptureEvent(horizonEventName) {
if (horizonEventName === 'onLostPointerCapture' || horizonEventName === 'onGotPointerCapture') {
return false;
}
return horizonEventName.slice(-7) === 'Capture';
}
// 事件懒委托,当用户定义事件后,再进行委托到根节点
export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
currentRoot.delegatedEvents.add(eventName);
@ -94,14 +102,6 @@ function getNativeEvtName(horizonEventName, capture) {
return nativeName.toLowerCase();
}
// 是否捕获事件
function isCaptureEvent(horizonEventName) {
if (horizonEventName === 'onLostPointerCapture' || horizonEventName === 'onGotPointerCapture') {
return false;
}
return horizonEventName.slice(-7) === 'Capture';
}
// 封装监听函数
function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) {
return event => {

View File

@ -23,6 +23,20 @@ interface Thenable {
then(resolve: (val?: any) => void, reject: (err: any) => void): void;
}
// 防止死循环
const LOOPING_LIMIT = 50;
let loopingCount = 0;
function callRenderQueue() {
callRenderQueueImmediate();
while (hasAsyncEffects() && loopingCount < LOOPING_LIMIT) {
loopingCount++;
runAsyncEffects();
// effects可能产生刷新任务这里再执行一次
callRenderQueueImmediate();
}
}
// act用于测试作用是如果fun触发了刷新包含了异步刷新可以保证在act后面的代码是在刷新完成后才执行。
function act(fun: () => void | Thenable): Thenable {
const funRet = asyncUpdates(fun);
@ -62,20 +76,6 @@ function act(fun: () => void | Thenable): Thenable {
}
}
// 防止死循环
const LOOPING_LIMIT = 50;
let loopingCount = 0;
function callRenderQueue() {
callRenderQueueImmediate();
while (hasAsyncEffects() && loopingCount < LOOPING_LIMIT) {
loopingCount++;
runAsyncEffects();
// effects可能产生刷新任务这里再执行一次
callRenderQueueImmediate();
}
}
export {
act
};

View File

@ -10,21 +10,6 @@ export function isPanelActive() {
return window['__HORIZON_DEV_HOOK__'];
}
// serializes store and creates expanded object with baked-in containing current computed values
function makeStoreSnapshot({ type, data }) {
const expanded = {};
Object.keys(data.store.$c).forEach(key => {
expanded[key] = data.store[key];
});
data.store.expanded = expanded;
const snapshot = makeProxySnapshot({
data,
type,
sessionId,
});
return snapshot;
}
// safely serializes variables containing values wrapped in Proxy object
function getType(value) {
if (!value) return 'nullish';
@ -39,6 +24,7 @@ function getType(value) {
if (typeof value === 'object') return 'object';
return 'primitive';
}
function makeProxySnapshot(obj, visited: any[] = []) {
const type = getType(obj);
let clone;
@ -112,6 +98,21 @@ function makeProxySnapshot(obj, visited: any[] = []) {
}
}
// serializes store and creates expanded object with baked-in containing current computed values
function makeStoreSnapshot({ type, data }) {
const expanded = {};
Object.keys(data.store.$c).forEach(key => {
expanded[key] = data.store[key];
});
data.store.expanded = expanded;
const snapshot = makeProxySnapshot({
data,
type,
sessionId,
});
return snapshot;
}
export const devtools = {
// returns vNode id from horizon devtools
getVNodeId: vNode => {

View File

@ -27,6 +27,10 @@ const proxyMap = new WeakMap();
export const hookObserverMap = new WeakMap();
export function getObserver(rawObj: any): Observer {
return rawObj[OBSERVER_KEY];
}
export function createProxy(rawObj: any, isHookObserver = true, listener: { current: (...args) => any }): any {
// 不是对象(是原始数据类型)不用代理
if (!(rawObj && isObject(rawObj))) {
@ -89,7 +93,3 @@ export function createProxy(rawObj: any, isHookObserver = true, listener: { curr
return proxyObj;
}
export function getObserver(rawObj: any): Observer {
return rawObj[OBSERVER_KEY];
}

View File

@ -19,6 +19,40 @@ import { resolveMutation } from '../../CommonUtils';
import { isPanelActive } from '../../devtools';
import { OBSERVER_KEY } from '../../Constants';
function set(rawObj: any[], key: string, value: any, receiver: any) {
const oldValue = rawObj[key];
const oldLength = rawObj.length;
const newValue = value;
const oldArray = isPanelActive() ? JSON.parse(JSON.stringify(rawObj)) : null;
const ret = Reflect.set(rawObj, key, newValue, receiver);
const newLength = rawObj.length;
const observer = getObserver(rawObj);
const mutation = isPanelActive() ? resolveMutation(oldArray, rawObj) : resolveMutation(null, rawObj);
if (!isSame(newValue, oldValue)) {
// 值不一样,触发监听器
if (observer.watchers?.[key]) {
observer.watchers[key].forEach(cb => {
cb(key, oldValue, newValue, mutation);
});
}
// 触发属性变化
observer.setProp(key, mutation);
}
if (oldLength !== newLength) {
// 触发数组的大小变化
observer.setProp('length', mutation);
}
return ret;
}
export function createArrayProxy(rawObj: any[], listener: { current: (...args) => any }): any[] {
let listeners = [] as ((...args) => void)[];
@ -118,37 +152,3 @@ export function createArrayProxy(rawObj: any[], listener: { current: (...args) =
return new Proxy(rawObj, handle);
}
function set(rawObj: any[], key: string, value: any, receiver: any) {
const oldValue = rawObj[key];
const oldLength = rawObj.length;
const newValue = value;
const oldArray = isPanelActive() ? JSON.parse(JSON.stringify(rawObj)) : null;
const ret = Reflect.set(rawObj, key, newValue, receiver);
const newLength = rawObj.length;
const observer = getObserver(rawObj);
const mutation = isPanelActive() ? resolveMutation(oldArray, rawObj) : resolveMutation(null, rawObj);
if (!isSame(newValue, oldValue)) {
// 值不一样,触发监听器
if (observer.watchers?.[key]) {
observer.watchers[key].forEach(cb => {
cb(key, oldValue, newValue, mutation);
});
}
// 触发属性变化
observer.setProp(key, mutation);
}
if (oldLength !== newLength) {
// 触发数组的大小变化
observer.setProp('length', mutation);
}
return ret;
}

View File

@ -25,48 +25,6 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
let oldData: [any, any][] = [];
let proxies = new Map();
function get(rawObj: { size: number }, key: any, receiver: any): any {
if (key === 'size') {
return size(rawObj);
}
if (key === 'get') {
return getFun.bind(null, rawObj);
}
if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver);
return value.bind(null, rawObj);
}
if (key === 'watch') {
const observer = getObserver(rawObj);
return (prop: any, handler: (key: string, oldValue: any, newValue: any) => void) => {
if (!observer.watchers[prop]) {
observer.watchers[prop] = [] as ((key: string, oldValue: any, newValue: any) => void)[];
}
observer.watchers[prop].push(handler);
return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
};
};
}
if (key === 'addListener') {
return listener => {
listeners.push(listener);
};
}
if (key === 'removeListener') {
return listener => {
listeners = listeners.filter(item => item != listener);
};
}
return Reflect.get(rawObj, key, receiver);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function getFun(rawObj: { get: (key: any) => any; has: (key: any) => boolean }, key: any) {
const keyProxy = rawObj.has(key) ? key : proxies.get(key);
@ -211,31 +169,6 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
return false;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function size(rawObj: { size: number }) {
const observer = getObserver(rawObj);
observer.useProp(COLLECTION_CHANGE);
return rawObj.size;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function keys(rawObj: { keys: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.keys(), 'keys');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function values(rawObj: { values: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.values(), 'values');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function entries(rawObj: { entries: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.entries(), 'entries');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function forOf(rawObj: {
entries: () => { next: () => { value: any; done: boolean } };
values: () => { next: () => { value: any; done: boolean } };
}) {
return wrapIterator(rawObj, rawObj.entries(), 'entries');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function forEach(
rawObj: { forEach: (callback: (value: any, key: any) => void) => void },
callback: (valProxy: any, keyProxy: any, rawObj: any) => void
@ -354,6 +287,75 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
},
};
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function size(rawObj: { size: number }) {
const observer = getObserver(rawObj);
observer.useProp(COLLECTION_CHANGE);
return rawObj.size;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function keys(rawObj: { keys: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.keys(), 'keys');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function values(rawObj: { values: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.values(), 'values');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function entries(rawObj: { entries: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.entries(), 'entries');
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function forOf(rawObj: {
entries: () => { next: () => { value: any; done: boolean } };
values: () => { next: () => { value: any; done: boolean } };
}) {
return wrapIterator(rawObj, rawObj.entries(), 'entries');
}
function get(rawObj: { size: number }, key: any, receiver: any): any {
if (key === 'size') {
return size(rawObj);
}
if (key === 'get') {
return getFun.bind(null, rawObj);
}
if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver);
return value.bind(null, rawObj);
}
if (key === 'watch') {
const observer = getObserver(rawObj);
return (prop: any, handler: (key: string, oldValue: any, newValue: any) => void) => {
if (!observer.watchers[prop]) {
observer.watchers[prop] = [] as ((key: string, oldValue: any, newValue: any) => void)[];
}
observer.watchers[prop].push(handler);
return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
};
};
}
if (key === 'addListener') {
return listener => {
listeners.push(listener);
};
}
if (key === 'removeListener') {
return listener => {
listeners = listeners.filter(item => item != listener);
};
}
return Reflect.get(rawObj, key, receiver);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,

View File

@ -18,6 +18,27 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler';
import { OBSERVER_KEY } from '../../Constants';
import { isPanelActive } from '../../devtools';
function set(rawObj: object, key: string, value: any, receiver: any): boolean {
const oldObject = isPanelActive() ? JSON.parse(JSON.stringify(rawObj)) : null;
const observer = getObserver(rawObj);
const oldValue = rawObj[key];
const newValue = value;
const ret = Reflect.set(rawObj, key, newValue, receiver);
const mutation = isPanelActive() ? resolveMutation(oldObject, rawObj) : resolveMutation(null, rawObj);
if (!isSame(newValue, oldValue)) {
if (observer.watchers?.[key]) {
observer.watchers[key].forEach(cb => {
cb(key, oldValue, newValue, mutation);
});
}
observer.setProp(key, mutation);
}
return ret;
}
export function createObjectProxy<T extends object>(
rawObj: T,
singleLevel = false,
@ -99,24 +120,3 @@ export function createObjectProxy<T extends object>(
return proxy;
}
function set(rawObj: object, key: string, value: any, receiver: any): boolean {
const oldObject = isPanelActive() ? JSON.parse(JSON.stringify(rawObj)) : null;
const observer = getObserver(rawObj);
const oldValue = rawObj[key];
const newValue = value;
const ret = Reflect.set(rawObj, key, newValue, receiver);
const mutation = isPanelActive() ? resolveMutation(oldObject, rawObj) : resolveMutation(null, rawObj);
if (!isSame(newValue, oldValue)) {
if (observer.watchers?.[key]) {
observer.watchers[key].forEach(cb => {
cb(key, oldValue, newValue, mutation);
});
}
observer.setProp(key, mutation);
}
return ret;
}

View File

@ -26,43 +26,6 @@ export function createSetProxy<T extends object>(
let listeners: ((mutation) => {})[] = [];
let proxies = new WeakMap();
function get(rawObj: { size: number }, key: any, receiver: any): any {
if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver);
return value.bind(null, rawObj);
}
if (key === 'size') {
return size(rawObj);
}
if (key === 'addListener') {
return listener => {
listeners.push(listener);
};
}
if (key === 'removeListener') {
return listener => {
listeners = listeners.filter(item => item != listener);
};
}
if (key === 'watch') {
const observer = getObserver(rawObj);
return (prop: any, handler: (key: string, oldValue: any, newValue: any) => void) => {
if (!observer.watchers[prop]) {
observer.watchers[prop] = [] as ((key: string, oldValue: any, newValue: any) => void)[];
}
observer.watchers[prop].push(handler);
return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
};
};
}
return Reflect.get(rawObj, key, receiver);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Set的add方法
function add(rawObj: { add: (any) => void; has: (any) => boolean; values: () => any[] }, value: any): Object {
if (!rawObj.has(proxies.get(value))) {
@ -166,17 +129,43 @@ export function createSetProxy<T extends object>(
return rawObj.size;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function keys(rawObj: { keys: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.keys());
}
function get(rawObj: { size: number }, key: any, receiver: any): any {
if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver);
return value.bind(null, rawObj);
}
function values(rawObj: { values: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.values());
}
if (key === 'size') {
return size(rawObj);
}
function entries(rawObj: { entries: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.entries());
if (key === 'addListener') {
return listener => {
listeners.push(listener);
};
}
if (key === 'removeListener') {
return listener => {
listeners = listeners.filter(item => item != listener);
};
}
if (key === 'watch') {
const observer = getObserver(rawObj);
return (prop: any, handler: (key: string, oldValue: any, newValue: any) => void) => {
if (!observer.watchers[prop]) {
observer.watchers[prop] = [] as ((key: string, oldValue: any, newValue: any) => void)[];
}
observer.watchers[prop].push(handler);
return () => {
observer.watchers[prop] = observer.watchers[prop].filter(cb => cb !== handler);
};
};
}
return Reflect.get(rawObj, key, receiver);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function wrapIterator(rawObj: Object, rawIt: { next: () => { value: any; done: boolean } }) {
const observer = getObserver(rawObj);
@ -224,6 +213,18 @@ export function createSetProxy<T extends object>(
};
}
function keys(rawObj: { keys: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.keys());
}
function values(rawObj: { values: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.values());
}
function entries(rawObj: { entries: () => { next: () => { value: any; done: boolean } } }) {
return wrapIterator(rawObj, rawObj.entries());
}
function forOf(rawObj: {
entries: () => { next: () => { value: any; done: boolean } };
values: () => { next: () => { value: any; done: boolean } };

View File

@ -53,6 +53,100 @@ const idGenerator = {
const storeMap = new Map<string, StoreObj<any, any, any>>();
// 通过该方法执行store.$queue中的action
function tryNextAction(storeObj, proxyObj, config, plannedActions) {
if (!plannedActions.length) {
if (proxyObj.$pending) {
const timestamp = Date.now();
const duration = timestamp - proxyObj.$pending;
proxyObj.$pending = false;
devtools.emit(QUEUE_FINISHED, {
store: storeObj,
endedAt: timestamp,
duration,
});
}
return;
}
const nextAction = plannedActions.shift()!;
const result = config.actions
? config.actions[nextAction.action].bind(storeObj, proxyObj)(...nextAction.payload)
: undefined;
if (isPromise(result)) {
result.then(value => {
nextAction.resolve(value);
tryNextAction(storeObj, proxyObj, config, plannedActions);
});
} else {
nextAction.resolve(result);
tryNextAction(storeObj, proxyObj, config, plannedActions);
}
}
// 删除Observers中保存的这个VNode的相关数据
export function clearVNodeObservers(vNode: VNode) {
if (!vNode.observers) {
return;
}
vNode.observers.forEach(observer => {
observer.clearByVNode(vNode);
});
vNode.observers.clear();
}
// 注册VNode销毁时的清理动作
function registerDestroyFunction() {
const processingVNode = getProcessingVNode();
// 获取不到当前运行的VNode说明不在组件中运行属于非法场景
if (!processingVNode) {
return;
}
if (!processingVNode.observers) {
processingVNode.observers = new Set<Observer>();
}
// 函数组件
if (processingVNode.tag === FunctionComponent) {
const vNodeRef = useRef(processingVNode);
useEffect(() => {
return () => {
clearVNodeObservers(vNodeRef.current);
vNodeRef.current.observers = null;
};
}, []);
} else if (processingVNode.tag === ClassComponent) {
// 类组件
if (!processingVNode.classComponentWillUnmount) {
processingVNode.classComponentWillUnmount = vNode => {
clearVNodeObservers(vNode);
vNode.observers = null;
};
}
}
}
// createStore返回的是一个getStore的函数这个函数必须要在组件函数/类组件里面被执行因为要注册VNode销毁时的清理动作
function createGetStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
storeObj: StoreObj<S, A, C>
): () => StoreObj<S, A, C> {
const getStore = () => {
if (!storeObj.$config.options?.isReduxAdapter) {
registerDestroyFunction();
}
return storeObj;
};
return getStore;
}
export function createStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
config: StoreConfig<S, A, C>
): () => StoreObj<S, A, C> {
@ -216,100 +310,6 @@ export function createStore<S extends object, A extends UserActions<S>, C extend
return createGetStore(storeObj);
}
// 通过该方法执行store.$queue中的action
function tryNextAction(storeObj, proxyObj, config, plannedActions) {
if (!plannedActions.length) {
if (proxyObj.$pending) {
const timestamp = Date.now();
const duration = timestamp - proxyObj.$pending;
proxyObj.$pending = false;
devtools.emit(QUEUE_FINISHED, {
store: storeObj,
endedAt: timestamp,
duration,
});
}
return;
}
const nextAction = plannedActions.shift()!;
const result = config.actions
? config.actions[nextAction.action].bind(storeObj, proxyObj)(...nextAction.payload)
: undefined;
if (isPromise(result)) {
result.then(value => {
nextAction.resolve(value);
tryNextAction(storeObj, proxyObj, config, plannedActions);
});
} else {
nextAction.resolve(result);
tryNextAction(storeObj, proxyObj, config, plannedActions);
}
}
// createStore返回的是一个getStore的函数这个函数必须要在组件函数/类组件里面被执行因为要注册VNode销毁时的清理动作
function createGetStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
storeObj: StoreObj<S, A, C>
): () => StoreObj<S, A, C> {
const getStore = () => {
if (!storeObj.$config.options?.isReduxAdapter) {
registerDestroyFunction();
}
return storeObj;
};
return getStore;
}
// 删除Observers中保存的这个VNode的相关数据
export function clearVNodeObservers(vNode: VNode) {
if (!vNode.observers) {
return;
}
vNode.observers.forEach(observer => {
observer.clearByVNode(vNode);
});
vNode.observers.clear();
}
// 注册VNode销毁时的清理动作
function registerDestroyFunction() {
const processingVNode = getProcessingVNode();
// 获取不到当前运行的VNode说明不在组件中运行属于非法场景
if (!processingVNode) {
return;
}
if (!processingVNode.observers) {
processingVNode.observers = new Set<Observer>();
}
// 函数组件
if (processingVNode.tag === FunctionComponent) {
const vNodeRef = useRef(processingVNode);
useEffect(() => {
return () => {
clearVNodeObservers(vNodeRef.current);
vNodeRef.current.observers = null;
};
}, []);
} else if (processingVNode.tag === ClassComponent) {
// 类组件
if (!processingVNode.classComponentWillUnmount) {
processingVNode.classComponentWillUnmount = vNode => {
clearVNodeObservers(vNode);
vNode.observers = null;
};
}
}
}
// 函数组件中使用的hook
export function useStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
id: string

View File

@ -228,6 +228,40 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
return node;
}
// 在局部更新时从上到下恢复父节点的context和PortalStack
function recoverTreeContext(vNode: VNode) {
const contextProviders: VNode[] = [];
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
contextProviders.unshift(parent);
}
if (parent.tag === DomPortal) {
pushCurrentRoot(parent);
}
parent = parent.parent;
}
contextProviders.forEach(node => {
setContext(node, node.props.value);
});
}
// 在局部更新时从下到上重置父节点的context
function resetTreeContext(vNode: VNode) {
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
resetContext(parent);
}
if (parent.tag === DomPortal) {
popCurrentRoot();
}
parent = parent.parent;
}
}
// ============================== 深度遍历 ==============================
function buildVNodeTree(treeRoot: VNode) {
const preMode = copyExecuteMode();
@ -299,40 +333,6 @@ function buildVNodeTree(treeRoot: VNode) {
setExecuteMode(preMode);
}
// 在局部更新时从上到下恢复父节点的context和PortalStack
function recoverTreeContext(vNode: VNode) {
const contextProviders: VNode[] = [];
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
contextProviders.unshift(parent);
}
if (parent.tag === DomPortal) {
pushCurrentRoot(parent);
}
parent = parent.parent;
}
contextProviders.forEach(node => {
setContext(node, node.props.value);
});
}
// 在局部更新时从下到上重置父节点的context
function resetTreeContext(vNode: VNode) {
let parent = vNode.parent;
while (parent !== null) {
if (parent.tag === ContextProvider) {
resetContext(parent);
}
if (parent.tag === DomPortal) {
popCurrentRoot();
}
parent = parent.parent;
}
}
// 总体任务入口
function renderFromRoot(treeRoot) {
runAsyncEffects();

View File

@ -231,6 +231,19 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
return null;
}
// 设置vNode中的cIndex属性cIndex是节点在children中的位置
function setVNodesCIndex(startChild: VNode | null, startIdx: number) {
let node: VNode | null = startChild;
let idx = startIdx;
while (node !== null) {
node.cIndex = idx;
markVNodePath(node);
node = node.next;
idx++;
}
}
// diff数组类型的节点核心算法
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
let resultingFirstChild: VNode | null = null;
@ -478,19 +491,6 @@ function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newC
return resultingFirstChild;
}
// 设置vNode中的cIndex属性cIndex是节点在children中的位置
function setVNodesCIndex(startChild: VNode | null, startIdx: number) {
let node: VNode | null = startChild;
let idx = startIdx;
while (node !== null) {
node.cIndex = idx;
markVNodePath(node);
node = node.next;
idx++;
}
}
// 新节点是迭代器类型
function diffIteratorNodesHandler(
parentNode: VNode,

View File

@ -182,47 +182,6 @@ function detachRef(vNode: VNode, isOldRef?: boolean) {
handleRef(vNode, ref, null);
}
// 卸载一个vNode不会递归
function unmountVNode(vNode: VNode): void {
switch (vNode.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent: {
callEffectRemove(vNode);
break;
}
case ClassComponent: {
detachRef(vNode);
const instance = vNode.realNode;
// 当constructor中抛出异常时instance会是null这里判断一下instance是否为空
// suspense打断时不需要触发WillUnmount
if (instance && typeof instance.componentWillUnmount === 'function' && !vNode.isSuspended) {
callComponentWillUnmount(vNode, instance);
}
// HorizonX会在classComponentWillUnmount中清除对VNode的引入用
if (vNode.classComponentWillUnmount) {
vNode.classComponentWillUnmount(vNode);
vNode.classComponentWillUnmount = null;
}
break;
}
case DomComponent: {
detachRef(vNode);
break;
}
case DomPortal: {
// 这里会递归
unmountDomComponents(vNode);
break;
}
default: {
break;
}
}
}
// 卸载vNode递归遍历子vNode
function unmountNestedVNodes(vNode: VNode): void {
travelVNodeTree(
@ -238,59 +197,6 @@ function unmountNestedVNodes(vNode: VNode): void {
);
}
function submitAddition(vNode: VNode): void {
let parent = vNode.parent;
let parentDom;
let tag;
while (parent !== null) {
tag = parent.tag;
if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) {
parentDom = parent.realNode;
break;
}
parent = parent.parent;
}
if ((parent.flags & ResetText) === ResetText) {
// 在insert之前先reset
clearText(parentDom);
FlagUtils.removeFlag(parent, ResetText);
}
if ((vNode.flags & DirectAddition) === DirectAddition) {
insertOrAppendPlacementNode(vNode, null, parentDom);
FlagUtils.removeFlag(vNode, DirectAddition);
return;
}
const before = getSiblingDom(vNode);
insertOrAppendPlacementNode(vNode, before, parentDom);
}
function insertOrAppendPlacementNode(node: VNode, beforeDom: Element | null, parent: Element | Container): void {
const { tag, realNode } = node;
if (isDomVNode(node)) {
insertDom(parent, realNode, beforeDom);
} else if (tag === DomPortal) {
// 这里不做处理直接在portal中处理
} else {
// 插入子节点们
let child = node.child;
while (child !== null) {
insertOrAppendPlacementNode(child, beforeDom, parent);
child = child.next;
}
}
}
function insertDom(parent, realNode, beforeDom) {
if (beforeDom) {
insertDomBefore(parent, realNode, beforeDom);
} else {
appendChildElement(parent, realNode);
}
}
// 遍历所有子节点删除dom节点detach ref 和 调用componentWillUnmount()
function unmountDomComponents(vNode: VNode): void {
let currentParentIsValid = false;
@ -342,6 +248,100 @@ function unmountDomComponents(vNode: VNode): void {
);
}
// 卸载一个vNode不会递归
function unmountVNode(vNode: VNode): void {
switch (vNode.tag) {
case FunctionComponent:
case ForwardRef:
case MemoComponent: {
callEffectRemove(vNode);
break;
}
case ClassComponent: {
detachRef(vNode);
const instance = vNode.realNode;
// 当constructor中抛出异常时instance会是null这里判断一下instance是否为空
// suspense打断时不需要触发WillUnmount
if (instance && typeof instance.componentWillUnmount === 'function' && !vNode.isSuspended) {
callComponentWillUnmount(vNode, instance);
}
// HorizonX会在classComponentWillUnmount中清除对VNode的引入用
if (vNode.classComponentWillUnmount) {
vNode.classComponentWillUnmount(vNode);
vNode.classComponentWillUnmount = null;
}
break;
}
case DomComponent: {
detachRef(vNode);
break;
}
case DomPortal: {
// 这里会递归
unmountDomComponents(vNode);
break;
}
default: {
break;
}
}
}
function insertDom(parent, realNode, beforeDom) {
if (beforeDom) {
insertDomBefore(parent, realNode, beforeDom);
} else {
appendChildElement(parent, realNode);
}
}
function insertOrAppendPlacementNode(node: VNode, beforeDom: Element | null, parent: Element | Container): void {
const { tag, realNode } = node;
if (isDomVNode(node)) {
insertDom(parent, realNode, beforeDom);
} else if (tag === DomPortal) {
// 这里不做处理直接在portal中处理
} else {
// 插入子节点们
let child = node.child;
while (child !== null) {
insertOrAppendPlacementNode(child, beforeDom, parent);
child = child.next;
}
}
}
function submitAddition(vNode: VNode): void {
let parent = vNode.parent;
let parentDom;
let tag;
while (parent !== null) {
tag = parent.tag;
if (tag === DomComponent || tag === TreeRoot || tag === DomPortal) {
parentDom = parent.realNode;
break;
}
parent = parent.parent;
}
if ((parent.flags & ResetText) === ResetText) {
// 在insert之前先reset
clearText(parentDom);
FlagUtils.removeFlag(parent, ResetText);
}
if ((vNode.flags & DirectAddition) === DirectAddition) {
insertOrAppendPlacementNode(vNode, null, parentDom);
FlagUtils.removeFlag(vNode, DirectAddition);
return;
}
const before = getSiblingDom(vNode);
insertOrAppendPlacementNode(vNode, before, parentDom);
}
function submitClear(vNode: VNode): void {
const realNode = vNode.realNode;
const cloneDom = realNode.cloneNode(false); // 复制节点后horizon添加给dom的属性未能复制
@ -397,6 +397,13 @@ function submitDeletion(vNode: VNode): void {
clearVNode(vNode);
}
function submitSuspenseComponent(vNode: VNode) {
const { childStatus } = vNode.suspenseState;
if (childStatus !== SuspenseChildStatus.Init) {
hideOrUnhideAllChildren(vNode.child, childStatus === SuspenseChildStatus.ShowFallback);
}
}
function submitUpdate(vNode: VNode): void {
switch (vNode.tag) {
case FunctionComponent:
@ -422,13 +429,6 @@ function submitUpdate(vNode: VNode): void {
}
}
function submitSuspenseComponent(vNode: VNode) {
const { childStatus } = vNode.suspenseState;
if (childStatus !== SuspenseChildStatus.Init) {
hideOrUnhideAllChildren(vNode.child, childStatus === SuspenseChildStatus.ShowFallback);
}
}
function submitResetTextContent(vNode: VNode) {
clearText(vNode.realNode);
}