@feng3d/watcher
Advanced tools
Comparing version 0.8.0 to 0.8.1
@@ -1,2 +0,361 @@ | ||
(function(d,g){typeof exports=="object"&&typeof module<"u"?g(exports):typeof define=="function"&&define.amd?define(["exports"],g):(d=typeof globalThis<"u"?globalThis:d||self,g(d.feng3d={}))})(this,function(d){"use strict";class g{constructor(){this._binds=[]}watch(t,n,e,h){Object.getOwnPropertyDescriptor(t,w)||Object.defineProperty(t,w,{value:{},enumerable:!1,configurable:!0,writable:!1});const s=n,c=t[w];if(!c[s]){const l=Object.getOwnPropertyDescriptor(t,s);c[s]={value:t[s],oldPropertyDescriptor:l,handlers:[]};let i=P(t,s);if(i&&i.set&&i.get){i={enumerable:i.enumerable,configurable:!0,get:i.get,set:i.set};const u=i.set;i.set=function(o){const _=this[s];_!==o&&(u&&u.call(this,o),v(o,_,this,s))}}else if(!i||!i.get&&!i.set)i={enumerable:!0,configurable:!0},i.get=function(){return this[w][s].value},i.set=function(u){const o=this[w][s].value;o!==u&&(this[w][s].value=u,v(u,o,this,s))};else{console.warn(`watch ${t} . ${s} 失败!`);return}Object.defineProperty(t,s,i)}const a=c[s];a.handlers.reduce((l,i)=>l||i.handler===e&&i.thisObject===h,!1)||a.handlers.push({handler:e,thisObject:h})}unwatch(t,n,e,h){const s=t[w];if(!s)return;const c=n;if(s[c]){const a=s[c].handlers;e===void 0&&(a.length=0);for(let r=a.length-1;r>=0;r--)a[r].handler===e&&(a[r].thisObject===h||h===void 0)&&a.splice(r,1);if(a.length===0){const r=t[c];delete t[c],s[c].oldPropertyDescriptor&&Object.defineProperty(t,c,s[c].oldPropertyDescriptor),t[c]=r,delete s[c]}Object.keys(s).length===0&&delete t[w]}}watchs(t,n,e,h){n.forEach(s=>{this.watch(t,s,e,h)})}unwatchs(t,n,e,h){n.forEach(s=>{this.unwatch(t,s,e,h)})}bind(t,n,e,h){const s=()=>{e[h]=t[n]},c=()=>{t[n]=e[h]};this.watch(t,n,s),this.watch(e,h,c),this._binds.push([t,n,s,e,h,c])}unbind(t,n,e,h){const s=this._binds;for(let c=s.length-1;c>=0;c--){const a=s[c];if((a[1]===n&&a[4]===h||a[1]===h&&a[4]===n)&&(a[0]===t&&a[3]===e||a[0]===e&&a[3]===t)){this.unwatch(a[0],a[1],a[2]),this.unwatch(a[3],a[4],a[5]),s.splice(c,1);break}}}watchchain(t,n,e,h){const s=n.indexOf(".");if(s===-1){this.watch(t,n,e,h);return}Object.getOwnPropertyDescriptor(t,O)||Object.defineProperty(t,O,{value:{},enumerable:!1,writable:!1,configurable:!0});const c=t[O];c[n]||(c[n]=[]);const a=c[n];if(!a.reduce((l,i)=>l||i.handler===e&&i.thisObject===h,!1)){const l=n.substr(0,s),i=n.substr(s+1);t[l]&&this.watchchain(t[l],i,e,h);const u=(o,_)=>{_&&this.unwatchchain(_,i,e,h),o&&this.watchchain(o,i,e,h);const x=y(_,i),D=y(o,i);x!==D&&e.call(h,D,x,o,i)};this.watch(t,l,u),a.push({handler:e,thisObject:h,watchchainFun:u})}}unwatchchain(t,n,e,h){const s=n.indexOf(".");if(s===-1){this.unwatch(t,n,e,h);return}const c=n.substr(0,s),a=n.substr(s+1),r=t[O];if(!r||!r[n])return;const l=r[n];for(let i=l.length-1;i>=0;i--){const u=l[i];(p(e)||e===u.handler&&h===u.thisObject)&&(t[c]&&this.unwatchchain(t[c],a,u.handler,u.thisObject),this.unwatch(t,c,u.watchchainFun),l.splice(i,1))}l.length===0&&delete r[n],Object.keys(r).length===0&&delete t[O]}watchobject(t,n,e,h){m(n).forEach(c=>{this.watchchain(t,c,e,h)})}unwatchobject(t,n,e,h){m(n).forEach(c=>{this.unwatchchain(t,c,e,h)})}}const E=new g,w="__watchs__",O="__watchchains__";function v(f,t,n,e){n[w][e].handlers.forEach(c=>{c.handler.call(c.thisObject,f,t,n,e)})}function P(f,t){const n=Object.getOwnPropertyDescriptor(f,t);if(n)return n;const e=Object.getPrototypeOf(f);if(e)return P(e,t)}function p(f){return f==null}function y(f,t){typeof t=="string"&&(t=t.split("."));let n=f;for(let e=0;e<t.length;e++){if(p(n))return;n=n[t[e]]}return n}function m(f){const t=[],n=Object.keys(f),e=new Array(n.length).fill(f),h=new Array(n.length).fill(-1);let s=0;for(;s<n.length;){const c=e[s],a=n[s],r=c[a];let l;if(p(r)||k(r)||(l=Object.keys(r)).length===0){const i=[a];let u=s;for(;(u=h[u])!==-1;)i.push(n[u]);i.reverse(),t.push(i.join("."))}else l.forEach(i=>{n.push(i),e.push(r),h.push(s)});s++}return t}function k(f){return f==null||typeof f=="boolean"||typeof f=="string"||typeof f=="number"}d.Watcher=g,d.watcher=E,Object.defineProperty(d,Symbol.toStringTag,{value:"Module"})}); | ||
(function(global, factory) { | ||
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.feng3d = {})); | ||
})(this, function(exports2) { | ||
"use strict"; | ||
class Watcher { | ||
constructor() { | ||
this._binds = []; | ||
} | ||
/** | ||
* 监听对象属性的变化 | ||
* | ||
* 注意:使用watch后获取该属性值的性能将会是原来的1/60,避免在运算密集处使用该函数。 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 | ||
* @param handler 变化回调函数 (newValue: V, oldValue: V, object: T, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
watch(object, property, handler, thisObject) { | ||
if (!Object.getOwnPropertyDescriptor(object, __watchs__)) { | ||
Object.defineProperty(object, __watchs__, { | ||
value: {}, | ||
enumerable: false, | ||
configurable: true, | ||
writable: false | ||
}); | ||
} | ||
const _property = property; | ||
const watchs = object[__watchs__]; | ||
if (!watchs[_property]) { | ||
const oldPropertyDescriptor = Object.getOwnPropertyDescriptor(object, _property); | ||
watchs[_property] = { value: object[_property], oldPropertyDescriptor, handlers: [] }; | ||
let data = getPropertyDescriptor(object, _property); | ||
if (data && data.set && data.get) { | ||
data = { enumerable: data.enumerable, configurable: true, get: data.get, set: data.set }; | ||
const orgSet = data.set; | ||
data.set = function(value) { | ||
const oldValue = this[_property]; | ||
if (oldValue !== value) { | ||
orgSet && orgSet.call(this, value); | ||
notifyListener(value, oldValue, this, _property); | ||
} | ||
}; | ||
} else if (!data || !data.get && !data.set) { | ||
data = { enumerable: true, configurable: true }; | ||
data.get = function() { | ||
return this[__watchs__][_property].value; | ||
}; | ||
data.set = function(value) { | ||
const oldValue = this[__watchs__][_property].value; | ||
if (oldValue !== value) { | ||
this[__watchs__][_property].value = value; | ||
notifyListener(value, oldValue, this, _property); | ||
} | ||
}; | ||
} else { | ||
console.warn(`watch ${object} . ${_property} 失败!`); | ||
return; | ||
} | ||
Object.defineProperty(object, _property, data); | ||
} | ||
const propertywatchs = watchs[_property]; | ||
const has = propertywatchs.handlers.reduce((v, item) => v || item.handler === handler && item.thisObject === thisObject, false); | ||
if (!has) { | ||
propertywatchs.handlers.push({ handler, thisObject }); | ||
} | ||
} | ||
/** | ||
* 取消监听对象属性的变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 | ||
* @param handler 变化回调函数 (newValue: V, oldValue: V, object: T, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
unwatch(object, property, handler, thisObject) { | ||
const watchs = object[__watchs__]; | ||
if (!watchs) | ||
return; | ||
const _property = property; | ||
if (watchs[_property]) { | ||
const handlers = watchs[_property].handlers; | ||
if (handler === void 0) { | ||
handlers.length = 0; | ||
} | ||
for (let i = handlers.length - 1; i >= 0; i--) { | ||
if (handlers[i].handler === handler && (handlers[i].thisObject === thisObject || thisObject === void 0)) { | ||
handlers.splice(i, 1); | ||
} | ||
} | ||
if (handlers.length === 0) { | ||
const value = object[_property]; | ||
delete object[_property]; | ||
if (watchs[_property].oldPropertyDescriptor) { | ||
Object.defineProperty(object, _property, watchs[_property].oldPropertyDescriptor); | ||
} | ||
object[_property] = value; | ||
delete watchs[_property]; | ||
} | ||
if (Object.keys(watchs).length === 0) { | ||
delete object[__watchs__]; | ||
} | ||
} | ||
} | ||
/** | ||
* 监听对象属性的变化 | ||
* | ||
* 注意:使用watch后获取该属性值的性能将会是原来的1/60,避免在运算密集处使用该函数。 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 | ||
* @param handler 变化回调函数 (newValue: V, oldValue: V, object: T, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
watchs(object, propertys, handler, thisObject) { | ||
propertys.forEach((v) => { | ||
this.watch(object, v, handler, thisObject); | ||
}); | ||
} | ||
/** | ||
* 取消监听对象属性的变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 | ||
* @param handler 变化回调函数 (newValue: V, oldValue: V, object: T, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
unwatchs(object, propertys, handler, thisObject) { | ||
propertys.forEach((v) => { | ||
this.unwatch(object, v, handler, thisObject); | ||
}); | ||
} | ||
/** | ||
* 绑定两个对象的指定属性,保存两个属性值同步。 | ||
* | ||
* @param object0 第一个对象。 | ||
* @param property0 第一个对象的属性名称。 | ||
* @param object1 第二个对象。 | ||
* @param property1 第二个对象的属性名称。 | ||
*/ | ||
bind(object0, property0, object1, property1) { | ||
const fun0 = () => { | ||
object1[property1] = object0[property0]; | ||
}; | ||
const fun1 = () => { | ||
object0[property0] = object1[property1]; | ||
}; | ||
this.watch(object0, property0, fun0); | ||
this.watch(object1, property1, fun1); | ||
this._binds.push([object0, property0, fun0, object1, property1, fun1]); | ||
} | ||
/** | ||
* 解除两个对象的指定属性的绑定。 | ||
* | ||
* @param object0 第一个对象。 | ||
* @param property0 第一个对象的属性名称。 | ||
* @param object1 第二个对象。 | ||
* @param property1 第二个对象的属性名称。 | ||
*/ | ||
unbind(object0, property0, object1, property1) { | ||
const binds = this._binds; | ||
for (let i = binds.length - 1; i >= 0; i--) { | ||
const v = binds[i]; | ||
if (v[1] === property0 && v[4] === property1 || v[1] === property1 && v[4] === property0) { | ||
if (v[0] === object0 && v[3] === object1 || v[0] === object1 && v[3] === object0) { | ||
this.unwatch(v[0], v[1], v[2]); | ||
this.unwatch(v[3], v[4], v[5]); | ||
binds.splice(i, 1); | ||
break; | ||
} | ||
} | ||
} | ||
} | ||
/** | ||
* 监听对象属性链值变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 例如:"a.b" | ||
* @param handler 变化回调函数 (newValue: any, oldValue: any, object: any, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
watchchain(object, property, handler, thisObject) { | ||
const notIndex = property.indexOf("."); | ||
if (notIndex === -1) { | ||
this.watch(object, property, handler, thisObject); | ||
return; | ||
} | ||
if (!Object.getOwnPropertyDescriptor(object, __watchchains__)) { | ||
Object.defineProperty(object, __watchchains__, { value: {}, enumerable: false, writable: false, configurable: true }); | ||
} | ||
const watchchains = object[__watchchains__]; | ||
if (!watchchains[property]) { | ||
watchchains[property] = []; | ||
} | ||
const propertywatchs = watchchains[property]; | ||
const has = propertywatchs.reduce((v, item) => v || item.handler === handler && item.thisObject === thisObject, false); | ||
if (!has) { | ||
const currentp = property.substr(0, notIndex); | ||
const nextp = property.substr(notIndex + 1); | ||
if (object[currentp]) { | ||
this.watchchain(object[currentp], nextp, handler, thisObject); | ||
} | ||
const watchchainFun = (newValue, oldValue) => { | ||
if (oldValue) | ||
this.unwatchchain(oldValue, nextp, handler, thisObject); | ||
if (newValue) | ||
this.watchchain(newValue, nextp, handler, thisObject); | ||
const ov = getObjectPropertyValue(oldValue, nextp); | ||
const nv = getObjectPropertyValue(newValue, nextp); | ||
if (ov !== nv) { | ||
handler.call(thisObject, nv, ov, newValue, nextp); | ||
} | ||
}; | ||
this.watch(object, currentp, watchchainFun); | ||
propertywatchs.push({ handler, thisObject, watchchainFun }); | ||
} | ||
} | ||
/** | ||
* 取消监听对象属性链值变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 例如:"a.b" | ||
* @param handler 变化回调函数 (object: T, property: string, oldValue: V) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
unwatchchain(object, property, handler, thisObject) { | ||
const notIndex = property.indexOf("."); | ||
if (notIndex === -1) { | ||
this.unwatch(object, property, handler, thisObject); | ||
return; | ||
} | ||
const currentp = property.substr(0, notIndex); | ||
const nextp = property.substr(notIndex + 1); | ||
const watchchains = object[__watchchains__]; | ||
if (!watchchains || !watchchains[property]) | ||
return; | ||
const propertywatchs = watchchains[property]; | ||
for (let i = propertywatchs.length - 1; i >= 0; i--) { | ||
const element = propertywatchs[i]; | ||
if (objectIsEmpty(handler) || handler === element.handler && thisObject === element.thisObject) { | ||
if (object[currentp]) { | ||
this.unwatchchain(object[currentp], nextp, element.handler, element.thisObject); | ||
} | ||
this.unwatch(object, currentp, element.watchchainFun); | ||
propertywatchs.splice(i, 1); | ||
} | ||
} | ||
if (propertywatchs.length === 0) | ||
delete watchchains[property]; | ||
if (Object.keys(watchchains).length === 0) { | ||
delete object[__watchchains__]; | ||
} | ||
} | ||
/** | ||
* 监听对象属性链值变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 例如:{a:{b:null,d:null}} 表示监听 object.a.b 与 object.a.d 值得变化,如果property===object时表示监听对象中所有叶子属性变化。 | ||
* @param handler 变化回调函数 (newValue: any, oldValue: any, host: any, property: string) => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
watchobject(object, property, handler, thisObject) { | ||
const chains = getObjectPropertyChains(property); | ||
chains.forEach((v) => { | ||
this.watchchain(object, v, handler, thisObject); | ||
}); | ||
} | ||
/** | ||
* 取消监听对象属性链值变化 | ||
* | ||
* @param object 被监听对象 | ||
* @param property 被监听属性 例如:{a:{b:null,d:null}} 表示监听 object.a.b 与 object.a.d 值得变化,如果property===object时表示监听对象中所有叶子属性变化。 | ||
* @param handler 变化回调函数 newValue: any, oldValue: any, host: any, property: string => void | ||
* @param thisObject 变化回调函数 this值 | ||
*/ | ||
unwatchobject(object, property, handler, thisObject) { | ||
const chains = getObjectPropertyChains(property); | ||
chains.forEach((v) => { | ||
this.unwatchchain(object, v, handler, thisObject); | ||
}); | ||
} | ||
} | ||
const watcher = new Watcher(); | ||
const __watchs__ = "__watchs__"; | ||
const __watchchains__ = "__watchchains__"; | ||
function notifyListener(newValue, oldValue, host, property) { | ||
const watchs = host[__watchs__]; | ||
const handlers = watchs[property].handlers; | ||
handlers.forEach((element) => { | ||
element.handler.call(element.thisObject, newValue, oldValue, host, property); | ||
}); | ||
} | ||
function getPropertyDescriptor(object, property) { | ||
const data = Object.getOwnPropertyDescriptor(object, property); | ||
if (data) { | ||
return data; | ||
} | ||
const prototype = Object.getPrototypeOf(object); | ||
if (prototype) { | ||
return getPropertyDescriptor(prototype, property); | ||
} | ||
return void 0; | ||
} | ||
function objectIsEmpty(obj) { | ||
if (obj === void 0 || obj === null) { | ||
return true; | ||
} | ||
return false; | ||
} | ||
function getObjectPropertyValue(object, property) { | ||
if (typeof property === "string") | ||
property = property.split("."); | ||
let value = object; | ||
for (let i = 0; i < property.length; i++) { | ||
if (objectIsEmpty(value)) | ||
return void 0; | ||
value = value[property[i]]; | ||
} | ||
return value; | ||
} | ||
function getObjectPropertyChains(object) { | ||
const result = []; | ||
const propertys = Object.keys(object); | ||
const hosts = new Array(propertys.length).fill(object); | ||
const parentPropertyIndices = new Array(propertys.length).fill(-1); | ||
let index = 0; | ||
while (index < propertys.length) { | ||
const host = hosts[index]; | ||
const cp = propertys[index]; | ||
const cv = host[cp]; | ||
let vks; | ||
if (objectIsEmpty(cv) || isBaseType(cv) || (vks = Object.keys(cv)).length === 0) { | ||
const ps = [cp]; | ||
let ci = index; | ||
while ((ci = parentPropertyIndices[ci]) !== -1) { | ||
ps.push(propertys[ci]); | ||
} | ||
ps.reverse(); | ||
result.push(ps.join(".")); | ||
} else { | ||
vks.forEach((k) => { | ||
propertys.push(k); | ||
hosts.push(cv); | ||
parentPropertyIndices.push(index); | ||
}); | ||
} | ||
index++; | ||
} | ||
return result; | ||
} | ||
function isBaseType(object) { | ||
if (object === void 0 || object === null || typeof object === "boolean" || typeof object === "string" || typeof object === "number") { | ||
return true; | ||
} | ||
return false; | ||
} | ||
exports2.Watcher = Watcher; | ||
exports2.watcher = watcher; | ||
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); | ||
}); | ||
//# sourceMappingURL=index.umd.js.map |
{ | ||
"name": "@feng3d/watcher", | ||
"version": "0.8.0", | ||
"version": "0.8.1", | ||
"description": "对象属性监听器", | ||
@@ -35,3 +35,4 @@ "main": "dist/index.umd.js", | ||
"src", | ||
"readme" | ||
"readme", | ||
"tsconfig.json" | ||
], | ||
@@ -38,0 +39,0 @@ "devDependencies": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
304020
23
2925