Match-id-0d2ee97c73eb3c17b73cacb842949e5fb6877812
This commit is contained in:
commit
e5f878bebf
|
@ -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',
|
||||
];
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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 => {
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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,18 +129,44 @@ 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);
|
||||
const hookObserver = hookObserverMap.get(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 } };
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue