Match-id-0d2ee97c73eb3c17b73cacb842949e5fb6877812
This commit is contained in:
commit
e5f878bebf
|
@ -13,6 +13,26 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* 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) {
|
function isNeedUnitCSS(styleName: string) {
|
||||||
return !(
|
return !(
|
||||||
noUnitCSS.includes(styleName) ||
|
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;
|
return listener;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 是否捕获事件
|
||||||
|
function isCaptureEvent(horizonEventName) {
|
||||||
|
if (horizonEventName === 'onLostPointerCapture' || horizonEventName === 'onGotPointerCapture') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return horizonEventName.slice(-7) === 'Capture';
|
||||||
|
}
|
||||||
|
|
||||||
// 事件懒委托,当用户定义事件后,再进行委托到根节点
|
// 事件懒委托,当用户定义事件后,再进行委托到根节点
|
||||||
export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
export function lazyDelegateOnRoot(currentRoot: VNode, eventName: string) {
|
||||||
currentRoot.delegatedEvents.add(eventName);
|
currentRoot.delegatedEvents.add(eventName);
|
||||||
|
@ -94,14 +102,6 @@ function getNativeEvtName(horizonEventName, capture) {
|
||||||
return nativeName.toLowerCase();
|
return nativeName.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 是否捕获事件
|
|
||||||
function isCaptureEvent(horizonEventName) {
|
|
||||||
if (horizonEventName === 'onLostPointerCapture' || horizonEventName === 'onGotPointerCapture') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return horizonEventName.slice(-7) === 'Capture';
|
|
||||||
}
|
|
||||||
|
|
||||||
// 封装监听函数
|
// 封装监听函数
|
||||||
function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) {
|
function getWrapperListener(horizonEventName, nativeEvtName, targetElement, listener) {
|
||||||
return event => {
|
return event => {
|
||||||
|
|
|
@ -23,6 +23,20 @@ interface Thenable {
|
||||||
then(resolve: (val?: any) => void, reject: (err: any) => void): void;
|
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后面的代码是在刷新完成后才执行。
|
// act用于测试,作用是:如果fun触发了刷新(包含了异步刷新),可以保证在act后面的代码是在刷新完成后才执行。
|
||||||
function act(fun: () => void | Thenable): Thenable {
|
function act(fun: () => void | Thenable): Thenable {
|
||||||
const funRet = asyncUpdates(fun);
|
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 {
|
export {
|
||||||
act
|
act
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,21 +10,6 @@ export function isPanelActive() {
|
||||||
return window['__HORIZON_DEV_HOOK__'];
|
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
|
// safely serializes variables containing values wrapped in Proxy object
|
||||||
function getType(value) {
|
function getType(value) {
|
||||||
if (!value) return 'nullish';
|
if (!value) return 'nullish';
|
||||||
|
@ -39,6 +24,7 @@ function getType(value) {
|
||||||
if (typeof value === 'object') return 'object';
|
if (typeof value === 'object') return 'object';
|
||||||
return 'primitive';
|
return 'primitive';
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeProxySnapshot(obj, visited: any[] = []) {
|
function makeProxySnapshot(obj, visited: any[] = []) {
|
||||||
const type = getType(obj);
|
const type = getType(obj);
|
||||||
let clone;
|
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 = {
|
export const devtools = {
|
||||||
// returns vNode id from horizon devtools
|
// returns vNode id from horizon devtools
|
||||||
getVNodeId: vNode => {
|
getVNodeId: vNode => {
|
||||||
|
|
|
@ -27,6 +27,10 @@ const proxyMap = new WeakMap();
|
||||||
|
|
||||||
export const hookObserverMap = 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 {
|
export function createProxy(rawObj: any, isHookObserver = true, listener: { current: (...args) => any }): any {
|
||||||
// 不是对象(是原始数据类型)不用代理
|
// 不是对象(是原始数据类型)不用代理
|
||||||
if (!(rawObj && isObject(rawObj))) {
|
if (!(rawObj && isObject(rawObj))) {
|
||||||
|
@ -89,7 +93,3 @@ export function createProxy(rawObj: any, isHookObserver = true, listener: { curr
|
||||||
|
|
||||||
return proxyObj;
|
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 { isPanelActive } from '../../devtools';
|
||||||
import { OBSERVER_KEY } from '../../Constants';
|
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[] {
|
export function createArrayProxy(rawObj: any[], listener: { current: (...args) => any }): any[] {
|
||||||
let listeners = [] as ((...args) => void)[];
|
let listeners = [] as ((...args) => void)[];
|
||||||
|
|
||||||
|
@ -118,37 +152,3 @@ export function createArrayProxy(rawObj: any[], listener: { current: (...args) =
|
||||||
|
|
||||||
return new Proxy(rawObj, handle);
|
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 oldData: [any, any][] = [];
|
||||||
let proxies = new Map();
|
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) {
|
function getFun(rawObj: { get: (key: any) => any; has: (key: any) => boolean }, key: any) {
|
||||||
const keyProxy = rawObj.has(key) ? key : proxies.get(key);
|
const keyProxy = rawObj.has(key) ? key : proxies.get(key);
|
||||||
|
@ -211,31 +169,6 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
|
||||||
return false;
|
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(
|
function forEach(
|
||||||
rawObj: { forEach: (callback: (value: any, key: any) => void) => void },
|
rawObj: { forEach: (callback: (value: any, key: any) => void) => void },
|
||||||
callback: (valProxy: any, keyProxy: any, rawObj: any) => 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 = {
|
const handler = {
|
||||||
get,
|
get,
|
||||||
|
|
|
@ -18,6 +18,27 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler';
|
||||||
import { OBSERVER_KEY } from '../../Constants';
|
import { OBSERVER_KEY } from '../../Constants';
|
||||||
import { isPanelActive } from '../../devtools';
|
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>(
|
export function createObjectProxy<T extends object>(
|
||||||
rawObj: T,
|
rawObj: T,
|
||||||
singleLevel = false,
|
singleLevel = false,
|
||||||
|
@ -99,24 +120,3 @@ export function createObjectProxy<T extends object>(
|
||||||
|
|
||||||
return proxy;
|
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 listeners: ((mutation) => {})[] = [];
|
||||||
let proxies = new WeakMap();
|
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方法
|
// Set的add方法
|
||||||
function add(rawObj: { add: (any) => void; has: (any) => boolean; values: () => any[] }, value: any): Object {
|
function add(rawObj: { add: (any) => void; has: (any) => boolean; values: () => any[] }, value: any): Object {
|
||||||
if (!rawObj.has(proxies.get(value))) {
|
if (!rawObj.has(proxies.get(value))) {
|
||||||
|
@ -166,18 +129,44 @@ export function createSetProxy<T extends object>(
|
||||||
return rawObj.size;
|
return rawObj.size;
|
||||||
}
|
}
|
||||||
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
function keys(rawObj: { keys: () => { next: () => { value: any; done: boolean } } }) {
|
function get(rawObj: { size: number }, key: any, receiver: any): any {
|
||||||
return wrapIterator(rawObj, rawObj.keys());
|
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 } } }) {
|
if (key === 'size') {
|
||||||
return wrapIterator(rawObj, rawObj.values());
|
return size(rawObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
function entries(rawObj: { entries: () => { next: () => { value: any; done: boolean } } }) {
|
if (key === 'addListener') {
|
||||||
return wrapIterator(rawObj, rawObj.entries());
|
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 } }) {
|
function wrapIterator(rawObj: Object, rawIt: { next: () => { value: any; done: boolean } }) {
|
||||||
const observer = getObserver(rawObj);
|
const observer = getObserver(rawObj);
|
||||||
const hookObserver = hookObserverMap.get(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: {
|
function forOf(rawObj: {
|
||||||
entries: () => { next: () => { value: any; done: boolean } };
|
entries: () => { next: () => { value: any; done: boolean } };
|
||||||
values: () => { 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>>();
|
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>>(
|
export function createStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
|
||||||
config: StoreConfig<S, A, C>
|
config: StoreConfig<S, A, C>
|
||||||
): () => StoreObj<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);
|
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
|
// 函数组件中使用的hook
|
||||||
export function useStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
|
export function useStore<S extends object, A extends UserActions<S>, C extends UserComputedValues<S>>(
|
||||||
id: string
|
id: string
|
||||||
|
|
|
@ -228,6 +228,40 @@ export function calcStartUpdateVNode(treeRoot: VNode) {
|
||||||
return node;
|
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) {
|
function buildVNodeTree(treeRoot: VNode) {
|
||||||
const preMode = copyExecuteMode();
|
const preMode = copyExecuteMode();
|
||||||
|
@ -299,40 +333,6 @@ function buildVNodeTree(treeRoot: VNode) {
|
||||||
setExecuteMode(preMode);
|
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) {
|
function renderFromRoot(treeRoot) {
|
||||||
runAsyncEffects();
|
runAsyncEffects();
|
||||||
|
|
|
@ -231,6 +231,19 @@ function getOldNodeFromMap(nodeMap: Map<string | number, VNode>, newIdx: number,
|
||||||
return null;
|
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数组类型的节点,核心算法
|
// diff数组类型的节点,核心算法
|
||||||
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
|
function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newChildren: Array<any>): VNode | null {
|
||||||
let resultingFirstChild: VNode | null = null;
|
let resultingFirstChild: VNode | null = null;
|
||||||
|
@ -478,19 +491,6 @@ function diffArrayNodesHandler(parentNode: VNode, firstChild: VNode | null, newC
|
||||||
return resultingFirstChild;
|
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(
|
function diffIteratorNodesHandler(
|
||||||
parentNode: VNode,
|
parentNode: VNode,
|
||||||
|
|
|
@ -182,47 +182,6 @@ function detachRef(vNode: VNode, isOldRef?: boolean) {
|
||||||
handleRef(vNode, ref, null);
|
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
|
// 卸载vNode,递归遍历子vNode
|
||||||
function unmountNestedVNodes(vNode: VNode): void {
|
function unmountNestedVNodes(vNode: VNode): void {
|
||||||
travelVNodeTree(
|
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()
|
// 遍历所有子节点:删除dom节点,detach ref 和 调用componentWillUnmount()
|
||||||
function unmountDomComponents(vNode: VNode): void {
|
function unmountDomComponents(vNode: VNode): void {
|
||||||
let currentParentIsValid = false;
|
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 {
|
function submitClear(vNode: VNode): void {
|
||||||
const realNode = vNode.realNode;
|
const realNode = vNode.realNode;
|
||||||
const cloneDom = realNode.cloneNode(false); // 复制节点后horizon添加给dom的属性未能复制
|
const cloneDom = realNode.cloneNode(false); // 复制节点后horizon添加给dom的属性未能复制
|
||||||
|
@ -397,6 +397,13 @@ function submitDeletion(vNode: VNode): void {
|
||||||
clearVNode(vNode);
|
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 {
|
function submitUpdate(vNode: VNode): void {
|
||||||
switch (vNode.tag) {
|
switch (vNode.tag) {
|
||||||
case FunctionComponent:
|
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) {
|
function submitResetTextContent(vNode: VNode) {
|
||||||
clearText(vNode.realNode);
|
clearText(vNode.realNode);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue