Match-id-63629d6cb470978c34a9bfafe90501013205792a

This commit is contained in:
* 2023-06-07 17:19:25 +08:00
commit 3f1eeba456
20 changed files with 339 additions and 294 deletions

View File

@ -73,7 +73,7 @@ function executeRender(children: any, container: Container, callback?: Callback)
} }
function findDOMNode(domOrEle?: Element): null | Element | Text { function findDOMNode(domOrEle?: Element): null | Element | Text {
if (domOrEle == null) { if (domOrEle === null || domOrEle === undefined) {
return null; return null;
} }
@ -103,7 +103,7 @@ function removeRootEventLister(container: Container) {
// 卸载入口 // 卸载入口
function destroy(container: Container): boolean { function destroy(container: Container): boolean {
if (container && container._treeRoot) { if (container._treeRoot) {
syncUpdates(() => { syncUpdates(() => {
executeRender(null, container, () => { executeRender(null, container, () => {
removeRootEventLister(container); removeRootEventLister(container);

View File

@ -46,7 +46,7 @@ function getChildNS(parentNS: string | null, tagName: string): string {
return NSS.html; return NSS.html;
} }
if (parentNS == null || parentNS === NSS.html) { if (parentNS === null || parentNS === NSS.html) {
// 没有父命名空间或父命名空间为xhtml // 没有父命名空间或父命名空间为xhtml
return NSS[tagName] ?? NSS.html; return NSS[tagName] ?? NSS.html;
} }
@ -130,7 +130,8 @@ export function isTextChild(type: string, props: Props): boolean {
return ( return (
props.dangerouslySetInnerHTML && props.dangerouslySetInnerHTML &&
typeof props.dangerouslySetInnerHTML === 'object' && typeof props.dangerouslySetInnerHTML === 'object' &&
props.dangerouslySetInnerHTML.__html != null props.dangerouslySetInnerHTML.__html !== null &&
props.dangerouslySetInnerHTML.__html !== undefined
); );
} }
} }
@ -148,7 +149,7 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
if (tag === DomComponent) { if (tag === DomComponent) {
// DomComponent类型 // DomComponent类型
if (element != null) { if (element !== null && element !== undefined) {
const type = vNode.type; const type = vNode.type;
const changeList = vNode.changeList; const changeList = vNode.changeList;
vNode.changeList = null; vNode.changeList = null;
@ -158,7 +159,14 @@ export function submitDomUpdate(tag: string, vNode: VNode) {
updateVNodeProps(element, newProps); updateVNodeProps(element, newProps);
// 应用diff更新Properties. // 应用diff更新Properties.
// 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false. // 当一个选中的radio改变名称,浏览器使另一个radio的复选框为false.
if (type === 'input' && newProps.type === 'radio' && newProps.name != null && newProps.checked != null) { if (
type === 'input'
&& newProps.type === 'radio'
&& newProps.name !== null
&& newProps.name !== undefined
&& newProps.checked !== null
&& newProps.checked !== undefined
) {
updateCommonProp(element, 'checked', newProps.checked, true); updateCommonProp(element, 'checked', newProps.checked, true);
} }
const isNativeTag = isNativeElement(type, newProps); const isNativeTag = isNativeElement(type, newProps);
@ -202,7 +210,7 @@ export function hideDom(tag: string, dom: Element | Text) {
} }
// 不隐藏元素 // 不隐藏元素
export function unHideDom(tag: string, dom: Element | Text, props: Props) { export function unHideDom(tag: string, dom: Element | Text, props?: Props) {
if (tag === DomComponent) { if (tag === DomComponent) {
dom.style.display = adjustStyleValue('display', props?.style?.display ?? ''); dom.style.display = adjustStyleValue('display', props?.style?.display ?? '');
} else if (tag === DomText) { } else if (tag === DomText) {

View File

@ -48,7 +48,7 @@ export function setDomProps(dom: Element, props: Object, isNativeTag: boolean, i
} }
} else if (propName === 'dangerouslySetInnerHTML') { } else if (propName === 'dangerouslySetInnerHTML') {
dom.innerHTML = propVal.__html; dom.innerHTML = propVal.__html;
} else if (!isInit || propVal != null) { } else if (!isInit || (propVal !== null && propVal !== undefined)) {
updateCommonProp(dom, propName, propVal, isNativeTag); updateCommonProp(dom, propName, propVal, isNativeTag);
} }
} }
@ -70,7 +70,7 @@ export function compareProps(oldProps: Object, newProps: Object): Object {
for (let i = 0; i < oldPropsLength; i++) { for (let i = 0; i < oldPropsLength; i++) {
propName = keysOfOldProps[i]; propName = keysOfOldProps[i];
// 新属性中包含该属性或者该属性为空值的属性不需要处理 // 新属性中包含该属性或者该属性为空值的属性不需要处理
if ( oldProps[propName] == null || keysOfNewProps.includes(propName)) { if ( oldProps[propName] === null || oldProps[propName] === undefined || keysOfNewProps.includes(propName)) {
continue; continue;
} }
@ -103,9 +103,13 @@ export function compareProps(oldProps: Object, newProps: Object): Object {
for (let i = 0; i < keysOfNewProps.length; i++) { for (let i = 0; i < keysOfNewProps.length; i++) {
propName = keysOfNewProps[i]; propName = keysOfNewProps[i];
newPropValue = newProps[propName]; newPropValue = newProps[propName];
oldPropValue = oldProps != null ? oldProps[propName] : null; oldPropValue = oldProps !== null && oldProps !== undefined ? oldProps[propName] : null;
if (newPropValue === oldPropValue || (newPropValue == null && oldPropValue == null)) { if (
newPropValue === oldPropValue
|| ((newPropValue === null || newPropValue === undefined)
&& (oldPropValue === null || oldPropValue === undefined))
) {
// 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理 // 新旧属性值未发生变化,或者新旧属性皆为空值,不需要进行处理
continue; continue;
} }
@ -140,7 +144,7 @@ export function compareProps(oldProps: Object, newProps: Object): Object {
} else if (propName === 'dangerouslySetInnerHTML') { } else if (propName === 'dangerouslySetInnerHTML') {
newHTML = newPropValue ? newPropValue.__html : undefined; newHTML = newPropValue ? newPropValue.__html : undefined;
oldHTML = oldPropValue ? oldPropValue.__html : undefined; oldHTML = oldPropValue ? oldPropValue.__html : undefined;
if (newHTML != null) { if (newHTML !== null && newHTML !== undefined) {
if (oldHTML !== newHTML) { if (oldHTML !== newHTML) {
toUpdateProps[propName] = newPropValue; toUpdateProps[propName] = newPropValue;
} }

View File

@ -67,7 +67,7 @@ export function adjustStyleValue(name, value) {
if (typeof value === 'number' && value !== 0 && isNeedUnitCSS(name)) { if (typeof value === 'number' && value !== 0 && isNeedUnitCSS(name)) {
validValue = `${value}px`; validValue = `${value}px`;
} else if (value === '' || value == null || typeof value === 'boolean') { } else if (value === '' || value === null || value === undefined || typeof value === 'boolean') {
validValue = ''; validValue = '';
} }

View File

@ -30,7 +30,7 @@ function setSelectionRange(dom: HTMLInputElement | HTMLTextAreaElement, range) {
const { start, end } = range; const { start, end } = range;
let realEnd = end; let realEnd = end;
if (realEnd == null) { if (realEnd === null || realEnd === undefined) {
realEnd = start; realEnd = start;
} }

View File

@ -21,44 +21,13 @@ import { BELONG_CLASS_VNODE_KEY } from '../renderer/vnode/VNode';
// 生成key // 生成key
function getItemKey(item: any, index: number): string { function getItemKey(item: any, index: number): string {
if (typeof item === 'object' && item !== null && item.key != null) { if (typeof item === 'object' && item !== null && item.key !== null && item.key !== undefined) {
return '.$' + item.key; return '.$' + item.key;
} }
// 使用36进制减少生成字符串的长度以节省空间 // 使用36进制减少生成字符串的长度以节省空间
return '.' + index.toString(36); return '.' + index.toString(36);
} }
function mapChildrenToArray(children: any, arr: Array<any>, prefix: string, callback?: Function): number | void {
const type = typeof children;
switch (type) {
// 继承原有规格undefined和boolean类型按照null处理
case 'undefined':
case 'boolean':
callMapFun(null, arr, prefix, callback);
return;
case 'number':
case 'string':
callMapFun(children, arr, prefix, callback);
return;
case 'object':
if (children === null) {
callMapFun(null, arr, prefix, callback);
return;
}
const vtype = children.vtype;
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
callMapFun(children, arr, prefix, callback);
return;
}
if (Array.isArray(children)) {
processArrayChildren(children, arr, prefix, callback);
return;
}
throw new Error('Object is invalid as a Horizon child. ');
// No Default
}
}
function processArrayChildren(children: any, arr: Array<any>, prefix: string, callback: Function) { function processArrayChildren(children: any, arr: Array<any>, prefix: string, callback: Function) {
for (let i = 0; i < children.length; i++) { for (let i = 0; i < children.length; i++) {
const childItem = children[i]; const childItem = children[i];
@ -93,6 +62,37 @@ function callMapFun(children: any, arr: Array<any>, prefix: string, callback: Fu
} }
} }
function mapChildrenToArray(children: any, arr: Array<any>, prefix: string, callback?: Function): number | void {
const type = typeof children;
switch (type) {
// 继承原有规格undefined和boolean类型按照null处理
case 'undefined':
case 'boolean':
callMapFun(null, arr, prefix, callback);
return;
case 'number':
case 'string':
callMapFun(children, arr, prefix, callback);
return;
case 'object':
if (children === null) {
callMapFun(null, arr, prefix, callback);
return;
}
const vtype = children.vtype;
if (vtype === TYPE_COMMON_ELEMENT || vtype === TYPE_PORTAL) {
callMapFun(children, arr, prefix, callback);
return;
}
if (Array.isArray(children)) {
processArrayChildren(children, arr, prefix, callback);
return;
}
throw new Error('Object is invalid as a Horizon child. ');
// No Default
}
}
// 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg // 在 children 里的每个直接子节点上调用一个函数,并将 this 设置为 thisArg
function mapChildren(children: any, func: Function, context?: any): Array<any> { function mapChildren(children: any, func: Function, context?: any): Array<any> {
if (children === null || children === undefined) { if (children === null || children === undefined) {

View File

@ -115,7 +115,8 @@ export function resolveMutation(from, to) {
if (res[i].mutation) found = true; if (res[i].mutation) found = true;
} }
} }
// TODO: resolve shifts
// need to resolve shifts
return { mutation: found, items: res, from, to }; return { mutation: found, items: res, from, to };
} }

View File

@ -140,7 +140,8 @@ export function createStore(reducer: Reducer, preloadedState?: any, enhancers?):
} }
export function combineReducers(reducers: { [key: string]: Reducer }): Reducer { export function combineReducers(reducers: { [key: string]: Reducer }): Reducer {
return (state = {}, action) => { return (state, action) => {
state = state || {};
const newState = {}; const newState = {};
Object.entries(reducers).forEach(([key, reducer]) => { Object.entries(reducers).forEach(([key, reducer]) => {
newState[key] = reducer(state[key], action); newState[key] = reducer(state[key], action);

View File

@ -116,18 +116,22 @@ function makeStoreSnapshot({ type, data }) {
export const devtools = { export const devtools = {
// returns vNode id from horizon devtools // returns vNode id from horizon devtools
getVNodeId: vNode => { getVNodeId: vNode => {
if (!isPanelActive()) return; if (!isPanelActive()) {
return null;
}
window['__HORIZON_DEV_HOOK__'].send(); // update list first window['__HORIZON_DEV_HOOK__'].send(); // update list first
return window['__HORIZON_DEV_HOOK__'].getVnodeId(vNode); return window['__HORIZON_DEV_HOOK__'].getVnodeId(vNode);
}, },
// sends horizonx devtool message to extension // sends horizonx devtool message to extension
emit: (type, data) => { emit: (type, data) => {
if (!isPanelActive()) return; if (!isPanelActive()) {
return;
}
window.postMessage({ window.postMessage({
type: 'HORIZON_DEV_TOOLS', type: 'HORIZON_DEV_TOOLS',
payload: makeStoreSnapshot({ type, data }), payload: makeStoreSnapshot({ type, data }),
from: 'dev tool hook', from: 'dev tool hook',
}); }, '');
}, },
}; };
@ -135,7 +139,7 @@ export const devtools = {
function getAffectedComponents() { function getAffectedComponents() {
const allStores = getAllStores(); const allStores = getAllStores();
const keys = Object.keys(allStores); const keys = Object.keys(allStores);
let res = {}; const res = {};
keys.forEach(key => { keys.forEach(key => {
if (!allStores[key].$config.state._horizonObserver.keyVNodes) { if (!allStores[key].$config.state._horizonObserver.keyVNodes) {
res[key] = []; res[key] = [];
@ -144,17 +148,17 @@ function getAffectedComponents() {
const subRes = new Set(); const subRes = new Set();
const process = Array.from(allStores[key].$config.state._horizonObserver.keyVNodes.values()); const process = Array.from(allStores[key].$config.state._horizonObserver.keyVNodes.values());
while (process.length) { while (process.length) {
let pivot = process.shift() as { tag: 'string' }; const pivot = process.shift() as { tag: 'string' };
if (pivot?.tag) subRes.add(pivot); if (pivot.tag) subRes.add(pivot);
if (pivot?.toString() === '[object Set]') Array.from(pivot).forEach(item => process.push(item)); if (pivot.toString() === '[object Set]') Array.from(pivot).forEach(item => process.push(item));
} }
res[key] = Array.from(subRes).map(vnode => { res[key] = Array.from(subRes).map(vNode => {
return { return {
name: vnode?.type name: vNode?.type
.toString() .toString()
.replace(/\{.*\}/, '{...}') .replace(/\{.*\}/, '{...}')
.replace('function ', ''), .replace('function ', ''),
nodeId: window.__HORIZON_DEV_HOOK__.getVnodeId(vnode), nodeId: window.__HORIZON_DEV_HOOK__.getVnodeId(vNode),
}; };
}); });
}); });
@ -163,7 +167,7 @@ function getAffectedComponents() {
} }
// listens to messages from background // listens to messages from background
window.addEventListener('message', messageEvent => { window.addEventListener('message', (messageEvent?) => {
if (messageEvent?.data?.payload?.type === 'horizonx request observed components') { if (messageEvent?.data?.payload?.type === 'horizonx request observed components') {
// get observed components // get observed components
setTimeout(() => { setTimeout(() => {
@ -171,7 +175,7 @@ window.addEventListener('message', messageEvent => {
type: 'HORIZON_DEV_TOOLS', type: 'HORIZON_DEV_TOOLS',
payload: { type: OBSERVED_COMPONENTS, data: getAffectedComponents() }, payload: { type: OBSERVED_COMPONENTS, data: getAffectedComponents() },
from: 'dev tool hook', from: 'dev tool hook',
}); }, '');
}, 100); }, 100);
} }
@ -192,7 +196,7 @@ window.addEventListener('message', messageEvent => {
const store = getStore(data.storeId); const store = getStore(data.storeId);
if (!store?.[data.action]) return; if (!store?.[data.action]) return;
const action = store.$queue?.[data.action]; const action = store.$queue[data.action];
const params = data.params; const params = data.params;
action(...params); action(...params);
} }
@ -216,6 +220,7 @@ window.addEventListener('message', messageEvent => {
console.error(err); console.error(err);
} }
} }
// TODO:implement add and delete element
// need to implement add and delete element
} }
}); });

View File

@ -41,9 +41,6 @@ export class HooklessObserver implements IObserver {
triggerChangeListeners(mutation: any): void { triggerChangeListeners(mutation: any): void {
this.listeners.forEach(listener => { this.listeners.forEach(listener => {
if (!listener) {
return;
}
listener(mutation); listener(mutation);
}); });
} }

View File

@ -81,7 +81,7 @@ export class Observer implements IObserver {
const vNodes = this.keyVNodes.get(key); const vNodes = this.keyVNodes.get(key);
//NOTE: using Set directly can lead to deadlock //NOTE: using Set directly can lead to deadlock
const vNodeArray = Array.from(vNodes || []); const vNodeArray = Array.from(vNodes || []);
vNodeArray?.forEach((vNode: VNode) => { vNodeArray.forEach((vNode: VNode) => {
if (vNode.isStoreChange) { if (vNode.isStoreChange) {
// VNode已经被触发过不再重复触发 // VNode已经被触发过不再重复触发
return; return;
@ -97,10 +97,6 @@ export class Observer implements IObserver {
} }
triggerUpdate(vNode: VNode): void { triggerUpdate(vNode: VNode): void {
if (!vNode) {
return;
}
// 触发VNode更新 // 触发VNode更新
launchUpdateFromVNode(vNode); launchUpdateFromVNode(vNode);
} }

View File

@ -31,7 +31,7 @@ export function getObserver(rawObj: any): Observer {
return rawObj[OBSERVER_KEY]; return rawObj[OBSERVER_KEY];
} }
export function createProxy(rawObj: any, isHookObserver = true, listener: { current: (...args) => any }): any { export function createProxy(rawObj: any, listener: { current: (...args) => any }, isHookObserver = true): any {
// 不是对象(是原始数据类型)不用代理 // 不是对象(是原始数据类型)不用代理
if (!(rawObj && isObject(rawObj))) { if (!(rawObj && isObject(rawObj))) {
return rawObj; return rawObj;
@ -60,11 +60,12 @@ export function createProxy(rawObj: any, isHookObserver = true, listener: { curr
// 创建Proxy // 创建Proxy
let proxyObj; let proxyObj;
if (!isHookObserver) { if (!isHookObserver) {
proxyObj = createObjectProxy(rawObj, true, { proxyObj = createObjectProxy(rawObj, {
current: change => { current: change => {
listener.current(change); listener.current(change);
}, },
}); },
true);
} else if (isArray(rawObj)) { } else if (isArray(rawObj)) {
// 数组 // 数组
proxyObj = createArrayProxy(rawObj as [], { proxyObj = createArrayProxy(rawObj as [], {
@ -74,18 +75,20 @@ export function createProxy(rawObj: any, isHookObserver = true, listener: { curr
}); });
} else if (isCollection(rawObj)) { } else if (isCollection(rawObj)) {
// 集合 // 集合
proxyObj = createCollectionProxy(rawObj, true, { proxyObj = createCollectionProxy(rawObj, {
current: change => { current: change => {
listener.current(change); listener.current(change);
}, },
}); },
true);
} else { } else {
// 原生对象 或 函数 // 原生对象 或 函数
proxyObj = createObjectProxy(rawObj, false, { proxyObj = createObjectProxy(rawObj, {
current: change => { current: change => {
listener?.current(change); listener.current(change);
}, },
}); },
false);
} }
proxyMap.set(rawObj, proxyObj); proxyMap.set(rawObj, proxyObj);

View File

@ -97,7 +97,7 @@ export function createArrayProxy(rawObj: any[], listener: { current: (...args) =
// 对于value也需要进一步代理 // 对于value也需要进一步代理
const valProxy = singleLevel const valProxy = singleLevel
? value ? value
: createProxy(value, hookObserverMap.get(rawObj), { : createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -108,7 +108,9 @@ export function createArrayProxy(rawObj: any[], listener: { current: (...args) =
listener.current(mutation); listener.current(mutation);
listeners.forEach(lst => lst(mutation)); listeners.forEach(lst => lst(mutation));
}, },
}); },
hookObserverMap.get(rawObj)
);
return valProxy; return valProxy;
} }

View File

@ -21,17 +21,17 @@ import { createMapProxy } from './MapProxy';
export function createCollectionProxy( export function createCollectionProxy(
rawObj: Object, rawObj: Object,
hookObserver = true, listener: { current: (...args) => any },
listener: { current: (...args) => any } hookObserver = true
): Object { ): Object {
if (isWeakSet(rawObj)) { if (isWeakSet(rawObj)) {
return createWeakSetProxy(rawObj, hookObserver, listener); return createWeakSetProxy(rawObj, listener, hookObserver);
} }
if (isSet(rawObj)) { if (isSet(rawObj)) {
return createSetProxy(rawObj, hookObserver, listener); return createSetProxy(rawObj, listener, hookObserver);
} }
if (isWeakMap(rawObj)) { if (isWeakMap(rawObj)) {
return createWeakMapProxy(rawObj, hookObserver, listener); return createWeakMapProxy(rawObj, listener, hookObserver);
} }
return createMapProxy(rawObj, hookObserver, listener); return createMapProxy(rawObj, listener, hookObserver);
} }

View File

@ -20,13 +20,17 @@ import { isPanelActive } from '../../devtools';
const COLLECTION_CHANGE = '_collectionChange'; const COLLECTION_CHANGE = '_collectionChange';
export function createMapProxy(rawObj: Object, hookObserver = true, listener: { current: (...args) => any }): Object { export function createMapProxy(
rawObj: Object,
listener: { current: (...args) => any },
hookObserver = true
): Object {
let listeners: ((mutation) => {})[] = []; let listeners: ((mutation) => {})[] = [];
let oldData: [any, any][] = []; let oldData: [any, any][] = [];
let proxies = new Map(); let proxies = new Map();
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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): any {
const keyProxy = rawObj.has(key) ? key : proxies.get(key); const keyProxy = rawObj.has(key) ? key : proxies.get(key);
if (!keyProxy) return; if (!keyProxy) return;
const observer = getObserver(rawObj); const observer = getObserver(rawObj);
@ -34,7 +38,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
const value = rawObj.get(keyProxy); const value = rawObj.get(keyProxy);
// 对于value也需要进一步代理 // 对于value也需要进一步代理
const valProxy = createProxy(value, hookObserverMap.get(rawObj), { const valProxy = createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -45,7 +49,9 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserverMap.get(rawObj)
);
return valProxy; return valProxy;
} }
@ -60,7 +66,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
}, },
key: any, key: any,
value: any value: any
) { ): any {
if (rawObj.has(key) || rawObj.has(proxies.get(key))) { if (rawObj.has(key) || rawObj.has(proxies.get(key))) {
// VALUE CHANGE (whole value for selected key is changed) // VALUE CHANGE (whole value for selected key is changed)
const oldValue = rawObj.get(proxies.get(key)); const oldValue = rawObj.get(proxies.get(key));
@ -70,7 +76,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
const observer = getObserver(rawObj); const observer = getObserver(rawObj);
observer.setProp(COLLECTION_CHANGE, mutation); observer.setProp(COLLECTION_CHANGE, mutation);
if (observer.watchers?.[key]) { if (observer.watchers[key]) {
observer.watchers[key].forEach(cb => { observer.watchers[key].forEach(cb => {
cb(key, oldValue, value, mutation); cb(key, oldValue, value, mutation);
}); });
@ -80,7 +86,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
oldData = [...Array.from(rawObj.entries())]; oldData = [...Array.from(rawObj.entries())];
} else { } else {
// NEW VALUE // NEW VALUE
const keyProxy = createProxy(key, hookObserverMap.get(rawObj), { const keyProxy = createProxy(key, {
current: change => { current: change => {
// KEY CHANGE // KEY CHANGE
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
@ -92,7 +98,9 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserverMap.get(rawObj)
);
proxies.set(key, keyProxy); proxies.set(key, keyProxy);
rawObj.set(keyProxy, value); rawObj.set(keyProxy, value);
@ -176,7 +184,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
const observer = getObserver(rawObj); const observer = getObserver(rawObj);
observer.useProp(COLLECTION_CHANGE); observer.useProp(COLLECTION_CHANGE);
rawObj.forEach((value, key) => { rawObj.forEach((value, key) => {
const keyProxy = createProxy(value, hookObserverMap.get(rawObj), { const keyProxy = createProxy(value, {
current: change => { current: change => {
//KEY ATTRIBUTES CHANGED //KEY ATTRIBUTES CHANGED
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
@ -188,8 +196,10 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
const valProxy = createProxy(key, hookObserverMap.get(rawObj), { hookObserverMap.get(rawObj)
);
const valProxy = createProxy(key, {
current: change => { current: change => {
// VALUE ATTRIBUTE CHANGED // VALUE ATTRIBUTE CHANGED
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
@ -201,7 +211,9 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserverMap.get(rawObj)
);
// 最后一个参数要返回代理对象 // 最后一个参数要返回代理对象
return callback(keyProxy, valProxy, rawObj); return callback(keyProxy, valProxy, rawObj);
}); });
@ -217,7 +229,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
const { value, done } = rawIt.next(); const { value, done } = rawIt.next();
if (done) { if (done) {
return { return {
value: createProxy(value, hookObserver, { value: createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -228,7 +240,9 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}), },
hookObserver
),
done, done,
}; };
} }
@ -238,7 +252,7 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
if (type === 'entries') { if (type === 'entries') {
//ENTRY CHANGED //ENTRY CHANGED
newVal = [ newVal = [
createProxy(value[0], hookObserver, { createProxy(value[0], {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -249,8 +263,10 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}), },
createProxy(value[1], hookObserver, { hookObserver
),
createProxy(value[1], {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -261,11 +277,13 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}), },
hookObserver
),
]; ];
} else { } else {
// SINGLE VALUE CHANGED // SINGLE VALUE CHANGED
newVal = createProxy(value, hookObserver, { newVal = createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -276,7 +294,9 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserver
);
} }
return { value: newVal, done }; return { value: newVal, done };
@ -314,6 +334,20 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
return wrapIterator(rawObj, rawObj.entries(), 'entries'); return wrapIterator(rawObj, rawObj.entries(), 'entries');
} }
const handler = {
get,
set,
delete: deleteFun,
clear,
has,
entries,
forEach,
keys,
values,
// 判断Symbol类型兼容IE
[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator']: forOf,
};
function get(rawObj: { size: number }, key: any, receiver: any): any { function get(rawObj: { size: number }, key: any, receiver: any): any {
if (key === 'size') { if (key === 'size') {
return size(rawObj); return size(rawObj);
@ -357,20 +391,6 @@ export function createMapProxy(rawObj: Object, hookObserver = true, listener: {
return Reflect.get(rawObj, key, receiver); return Reflect.get(rawObj, key, receiver);
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,
set,
delete: deleteFun,
clear,
has,
entries,
forEach,
keys,
values,
// 判断Symbol类型兼容IE
[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator']: forOf,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const boundHandler = {}; const boundHandler = {};
Object.entries(handler).forEach(([id, val]) => { Object.entries(handler).forEach(([id, val]) => {
boundHandler[id] = (...args: any[]) => { boundHandler[id] = (...args: any[]) => {

View File

@ -41,8 +41,8 @@ function set(rawObj: object, key: string, value: any, receiver: any): boolean {
export function createObjectProxy<T extends object>( export function createObjectProxy<T extends object>(
rawObj: T, rawObj: T,
singleLevel = false, listener: { current: (...args) => any },
listener: { current: (...args) => any } singleLevel = false
): ProxyHandler<T> { ): ProxyHandler<T> {
let listeners = [] as ((...args) => void)[]; let listeners = [] as ((...args) => void)[];
@ -87,7 +87,7 @@ export function createObjectProxy<T extends object>(
// 对于value也需要进一步代理 // 对于value也需要进一步代理
const valProxy = singleLevel const valProxy = singleLevel
? value ? value
: createProxy(value, hookObserverMap.get(rawObj), { : createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -98,7 +98,9 @@ export function createObjectProxy<T extends object>(
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserverMap.get(rawObj)
);
return valProxy; return valProxy;
} }

View File

@ -20,8 +20,8 @@ const COLLECTION_CHANGE = '_collectionChange';
export function createSetProxy<T extends object>( export function createSetProxy<T extends object>(
rawObj: T, rawObj: T,
hookObserver = true, listener: { current: (...args) => any },
listener: { current: (...args) => any } hookObserver = true
): ProxyHandler<T> { ): ProxyHandler<T> {
let listeners: ((mutation) => {})[] = []; let listeners: ((mutation) => {})[] = [];
let proxies = new WeakMap(); let proxies = new WeakMap();
@ -29,7 +29,7 @@ export function createSetProxy<T extends object>(
// 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))) {
const proxy = createProxy(value, hookObserverMap.get(rawObj), { const proxy = createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -48,7 +48,9 @@ export function createSetProxy<T extends object>(
}) })
); );
}, },
}); },
hookObserverMap.get(rawObj)
);
const oldValues = Array.from(rawObj.values()); const oldValues = Array.from(rawObj.values());
proxies.set(value, proxy); proxies.set(value, proxy);
@ -129,6 +131,20 @@ export function createSetProxy<T extends object>(
return rawObj.size; return rawObj.size;
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,
add,
delete: deleteFun,
has,
clear,
forEach,
forOf,
entries,
keys,
values,
[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator']: forOf,
};
function get(rawObj: { size: number }, key: any, receiver: any): any { function get(rawObj: { size: number }, key: any, receiver: any): any {
if (Object.prototype.hasOwnProperty.call(handler, key)) { if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver); const value = Reflect.get(handler, key, receiver);
@ -196,13 +212,13 @@ export function createSetProxy<T extends object>(
}; };
const { value, done } = rawIt.next(); const { value, done } = rawIt.next();
if (done) { if (done) {
return { value: createProxy(value, hookObserver, currentListener), done }; return { value: createProxy(value, currentListener, hookObserver), done };
} }
observer.useProp(COLLECTION_CHANGE); observer.useProp(COLLECTION_CHANGE);
let newVal; let newVal;
newVal = createProxy(value, hookObserver, currentListener); newVal = createProxy(value, currentListener, hookObserver);
return { value: newVal, done }; return { value: newVal, done };
}, },
@ -260,27 +276,13 @@ export function createSetProxy<T extends object>(
); );
}, },
}; };
const valProxy = createProxy(value, hookObserverMap.get(rawObj), currentListener); const valProxy = createProxy(value, currentListener, hookObserverMap.get(rawObj));
const keyProxy = createProxy(key, hookObserverMap.get(rawObj), currentListener); const keyProxy = createProxy(key, currentListener, hookObserverMap.get(rawObj));
// 最后一个参数要返回代理对象 // 最后一个参数要返回代理对象
return callback(valProxy, keyProxy, rawObj); return callback(valProxy, keyProxy, rawObj);
}); });
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,
add,
delete: deleteFun,
has,
clear,
forEach,
forOf,
entries,
keys,
values,
[typeof Symbol === 'function' ? Symbol.iterator : '@@iterator']: forOf,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
getObserver(rawObj).addListener(change => { getObserver(rawObj).addListener(change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);

View File

@ -22,11 +22,44 @@ const COLLECTION_CHANGE = '_collectionChange';
export function createWeakMapProxy( export function createWeakMapProxy(
rawObj: Object, rawObj: Object,
hookObserver = true, listener: { current: (...args) => any },
listener: { current: (...args) => any } hookObserver = true
): Object { ): Object {
let listeners: ((mutation) => {})[] = []; let listeners: ((mutation) => {})[] = [];
const handler = {
get,
set,
add,
delete: deleteFun,
clear,
has,
};
function getFun(rawObj: { get: (key: any) => any }, key: any) {
const observer = getObserver(rawObj);
observer.useProp(key);
const value = rawObj.get(key);
// 对于value也需要进一步代理
const valProxy = createProxy(value, {
current: change => {
if (!change.parents) change.parents = [];
change.parents.push(rawObj);
let mutation = resolveMutation(
{ ...rawObj, [key]: change.mutation.from },
{ ...rawObj, [key]: change.mutation.to }
);
listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation }));
},
},
hookObserverMap.get(rawObj)
);
return valProxy;
}
function get(rawObj: { size: number }, key: any, receiver: any): any { function get(rawObj: { size: number }, key: any, receiver: any): any {
if (key === 'get') { if (key === 'get') {
return getFun.bind(null, rawObj); return getFun.bind(null, rawObj);
@ -66,28 +99,6 @@ export function createWeakMapProxy(
return Reflect.get(rawObj, key, receiver); return Reflect.get(rawObj, key, receiver);
} }
function getFun(rawObj: { get: (key: any) => any }, key: any) {
const observer = getObserver(rawObj);
observer.useProp(key);
const value = rawObj.get(key);
// 对于value也需要进一步代理
const valProxy = createProxy(value, hookObserverMap.get(rawObj), {
current: change => {
if (!change.parents) change.parents = [];
change.parents.push(rawObj);
let mutation = resolveMutation(
{ ...rawObj, [key]: change.mutation.from },
{ ...rawObj, [key]: change.mutation.to }
);
listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation }));
},
});
return valProxy;
}
// Map的set方法 // Map的set方法
function set( function set(
rawObj: { get: (key: any) => any; set: (key: any, value: any) => any; has: (key: any) => boolean }, rawObj: { get: (key: any) => any; set: (key: any, value: any) => any; has: (key: any) => boolean },
@ -171,15 +182,6 @@ export function createWeakMapProxy(
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,
set,
add,
delete: deleteFun,
clear,
has,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
getObserver(rawObj).addListener(change => { getObserver(rawObj).addListener(change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);

View File

@ -18,12 +18,19 @@ import { createProxy, getObserver, hookObserverMap } from '../ProxyHandler';
export function createWeakSetProxy<T extends object>( export function createWeakSetProxy<T extends object>(
rawObj: T, rawObj: T,
listener: { current: (...args) => any },
hookObserver = true, hookObserver = true,
listener: { current: (...args) => any }
): ProxyHandler<T> { ): ProxyHandler<T> {
let listeners: ((mutation) => {})[] = []; let listeners: ((mutation) => {})[] = [];
let proxies = new WeakMap(); let proxies = new WeakMap();
const handler = {
get,
add,
delete: deleteFun,
has,
};
function get(rawObj: { size: number }, key: any, receiver: any): any { function get(rawObj: { size: number }, key: any, receiver: any): any {
if (Object.prototype.hasOwnProperty.call(handler, key)) { if (Object.prototype.hasOwnProperty.call(handler, key)) {
const value = Reflect.get(handler, key, receiver); const value = Reflect.get(handler, key, receiver);
@ -59,7 +66,7 @@ export function createWeakSetProxy<T extends object>(
// Set的add方法 // Set的add方法
function add(rawObj: { add: (any) => void; has: (any) => boolean }, value: any): Object { function add(rawObj: { add: (any) => void; has: (any) => boolean }, value: any): Object {
if (!rawObj.has(proxies.get(value))) { if (!rawObj.has(proxies.get(value))) {
const proxy = createProxy(value, hookObserverMap.get(rawObj), { const proxy = createProxy(value, {
current: change => { current: change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);
@ -70,7 +77,9 @@ export function createWeakSetProxy<T extends object>(
listener.current({ ...change, mutation }); listener.current({ ...change, mutation });
listeners.forEach(lst => lst({ ...change, mutation })); listeners.forEach(lst => lst({ ...change, mutation }));
}, },
}); },
hookObserverMap.get(rawObj)
);
proxies.set(value, proxy); proxies.set(value, proxy);
@ -109,13 +118,6 @@ export function createWeakSetProxy<T extends object>(
return false; return false;
} }
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
const handler = {
get,
add,
delete: deleteFun,
has,
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
getObserver(rawObj).addListener(change => { getObserver(rawObj).addListener(change => {
if (!change.parents) change.parents = []; if (!change.parents) change.parents = [];
change.parents.push(rawObj); change.parents.push(rawObj);

View File

@ -161,7 +161,7 @@ export function createStore<S extends object, A extends UserActions<S>, C extend
current: listener => {}, current: listener => {},
}; };
const proxyObj = createProxy(config.state, !config.options?.isReduxAdapter, listener); const proxyObj = createProxy(config.state, listener, !config.options?.isReduxAdapter);
proxyObj.$pending = false; proxyObj.$pending = false;