diff --git a/libs/horizon/index.ts b/libs/horizon/index.ts index efe6df6b..90c536d5 100644 --- a/libs/horizon/index.ts +++ b/libs/horizon/index.ts @@ -69,6 +69,7 @@ import { } from './src/dom/DOMExternal'; import { syncUpdates as flushSync } from './src/renderer/TreeBuilder'; +import { toRaw } from './src/horizonx/proxy/ProxyHandler'; const Horizon = { Children, @@ -157,6 +158,7 @@ export { clearStore, reduxAdapter, watch, + toRaw, // 兼容ReactIs isFragment, isElement, diff --git a/libs/horizon/src/horizonx/Constants.ts b/libs/horizon/src/horizonx/Constants.ts index 6d65ab52..ded649bd 100644 --- a/libs/horizon/src/horizonx/Constants.ts +++ b/libs/horizon/src/horizonx/Constants.ts @@ -13,4 +13,6 @@ * See the Mulan PSL v2 for more details. */ -export const OBSERVER_KEY = '_horizonObserver'; +export const OBSERVER_KEY = typeof Symbol === 'function' ? Symbol('_horizonObserver') : '_horizonObserver'; + +export const RAW_VALUE = '_rawValue'; diff --git a/libs/horizon/src/horizonx/proxy/ProxyHandler.ts b/libs/horizon/src/horizonx/proxy/ProxyHandler.ts index d37cca1a..6d4027af 100644 --- a/libs/horizon/src/horizonx/proxy/ProxyHandler.ts +++ b/libs/horizon/src/horizonx/proxy/ProxyHandler.ts @@ -20,7 +20,7 @@ import { isArray, isCollection, isObject } from '../CommonUtils'; import { createArrayProxy } from './handlers/ArrayProxyHandler'; import { createCollectionProxy } from './handlers/CollectionProxyHandler'; import type { IObserver } from '../types'; -import { OBSERVER_KEY } from '../Constants'; +import { OBSERVER_KEY, RAW_VALUE } from '../Constants'; // 保存rawObj -> Proxy const proxyMap = new WeakMap(); @@ -31,6 +31,18 @@ export function getObserver(rawObj: any): Observer { return rawObj[OBSERVER_KEY]; } +const setObserverKey = typeof OBSERVER_KEY === 'string' + ? (rawObj, observer) => { + Object.defineProperty(rawObj, OBSERVER_KEY, { + configurable: false, + enumerable: false, + value: observer, + }); + } + : (rawObj, observer) => { + rawObj[OBSERVER_KEY] = observer; + }; + export function createProxy(rawObj: any, listener: { current: (...args) => any }, isHookObserver = true): any { // 不是对象(是原始数据类型)不用代理 if (!(rawObj && isObject(rawObj))) { @@ -52,7 +64,7 @@ export function createProxy(rawObj: any, listener: { current: (...args) => any } let observer: IObserver = getObserver(rawObj); if (!observer) { observer = isHookObserver ? new Observer() : new HooklessObserver(); - rawObj[OBSERVER_KEY] = observer; + setObserverKey(rawObj, observer); } hookObserverMap.set(rawObj, isHookObserver); @@ -96,3 +108,7 @@ export function createProxy(rawObj: any, listener: { current: (...args) => any } return proxyObj; } + +export function toRaw(observed: T): T { + return observed && (observed)[RAW_VALUE]; +} diff --git a/libs/horizon/src/horizonx/proxy/handlers/ArrayProxyHandler.ts b/libs/horizon/src/horizonx/proxy/handlers/ArrayProxyHandler.ts index ea94e4a0..c5aa46e3 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/ArrayProxyHandler.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/ArrayProxyHandler.ts @@ -17,7 +17,7 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; import { isSame, isValidIntegerKey } from '../../CommonUtils'; import { resolveMutation } from '../../CommonUtils'; import { isPanelActive } from '../../devtools'; -import { OBSERVER_KEY } from '../../Constants'; +import { OBSERVER_KEY, RAW_VALUE } from '../../Constants'; function set(rawObj: any[], key: string, value: any, receiver: any) { const oldValue = rawObj[key]; @@ -137,6 +137,10 @@ export function createArrayProxy(rawObj: any[], listener: { current: (...args) = return objectGet(rawObj, key, receiver); } + if (key === RAW_VALUE) { + return rawObj; + } + return Reflect.get(rawObj, key, receiver); } diff --git a/libs/horizon/src/horizonx/proxy/handlers/MapProxy.ts b/libs/horizon/src/horizonx/proxy/handlers/MapProxy.ts index 03accb28..8529f35c 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/MapProxy.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/MapProxy.ts @@ -17,6 +17,7 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; import { isSame } from '../../CommonUtils'; import { resolveMutation } from '../../CommonUtils'; import { isPanelActive } from '../../devtools'; +import { RAW_VALUE } from '../../Constants'; const COLLECTION_CHANGE = '_collectionChange'; @@ -388,6 +389,10 @@ export function createMapProxy( }; } + if (key === RAW_VALUE) { + return rawObj; + } + return Reflect.get(rawObj, key, receiver); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/horizon/src/horizonx/proxy/handlers/ObjectProxyHandler.ts b/libs/horizon/src/horizonx/proxy/handlers/ObjectProxyHandler.ts index 1a216477..0244bbdf 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/ObjectProxyHandler.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/ObjectProxyHandler.ts @@ -15,7 +15,7 @@ import { isSame, resolveMutation } from '../../CommonUtils'; import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; -import { OBSERVER_KEY } from '../../Constants'; +import { OBSERVER_KEY, RAW_VALUE } from '../../Constants'; import { isPanelActive } from '../../devtools'; function set(rawObj: object, key: string, value: any, receiver: any): boolean { @@ -78,6 +78,10 @@ export function createObjectProxy( }; } + if (key === RAW_VALUE) { + return rawObj; + } + observer.useProp(key); const value = Reflect.get(rawObj, key, receiver); diff --git a/libs/horizon/src/horizonx/proxy/handlers/SetProxy.ts b/libs/horizon/src/horizonx/proxy/handlers/SetProxy.ts index e5b19e4f..933ad73c 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/SetProxy.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/SetProxy.ts @@ -15,6 +15,7 @@ import { resolveMutation } from '../../CommonUtils'; import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; +import { RAW_VALUE } from '../../Constants'; const COLLECTION_CHANGE = '_collectionChange'; @@ -179,6 +180,11 @@ export function createSetProxy( }; }; } + + if (key === RAW_VALUE) { + return rawObj; + } + return Reflect.get(rawObj, key, receiver); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/libs/horizon/src/horizonx/proxy/handlers/WeakMapProxy.ts b/libs/horizon/src/horizonx/proxy/handlers/WeakMapProxy.ts index 70124cb6..0c818b3c 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/WeakMapProxy.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/WeakMapProxy.ts @@ -17,6 +17,7 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; import { isSame } from '../../CommonUtils'; import { resolveMutation } from '../../CommonUtils'; import { isPanelActive } from '../../devtools'; +import { RAW_VALUE } from '../../Constants'; const COLLECTION_CHANGE = '_collectionChange'; @@ -96,6 +97,10 @@ export function createWeakMapProxy( }; } + if (key === RAW_VALUE) { + return rawObj; + } + return Reflect.get(rawObj, key, receiver); } diff --git a/libs/horizon/src/horizonx/proxy/handlers/WeakSetProxy.ts b/libs/horizon/src/horizonx/proxy/handlers/WeakSetProxy.ts index baaa6a2b..e1a843cd 100644 --- a/libs/horizon/src/horizonx/proxy/handlers/WeakSetProxy.ts +++ b/libs/horizon/src/horizonx/proxy/handlers/WeakSetProxy.ts @@ -15,6 +15,7 @@ import { resolveMutation } from '../../CommonUtils'; import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler'; +import { RAW_VALUE } from '../../Constants'; export function createWeakSetProxy( rawObj: T, @@ -60,6 +61,11 @@ export function createWeakSetProxy( }; }; } + + if (key === RAW_VALUE) { + return rawObj; + } + return Reflect.get(rawObj, key, receiver); } //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////