我创建了两个装饰器,一个附加到一个方法,该方法在对象上创建一个属性,并将一个函数附加到该对象,以便稍后添加到事件侦听器中。
它看起来像这样:
export const EVENT_BINDING_PREFIX = '__attachEventBinding_'
export function Event(listenerLocation: string) {
return (target: any, propertyKey: string, descriptor: PropertyDescriptor) => {
return Object.defineProperty(target, `${EVENT_BINDING_PREFIX}${propertyKey}`, {
configurable: true,
value: {
type: 'event',
name: listenerLocation.split(':'),
binding: descriptor.value
}
})
}
}
接下来,我有一个扩展它所附加到的对象的绑定。当对象被实例化时,它会添加从上述函数创建的绑定。
export function GameObject(options?: object) {
return function <T extends { new(...args: any[]): object }>(constructor: T) {
return class extends constructor {
constructor(...args: any[]) {
super(...args)
this.addBindings()
}
get bindings() {
return Object.getOwnPropertyNames(Object.getPrototypeOf(Object.getPrototypeOf(this)))
.filter(i => i.startsWith(EVENT_BINDING_PREFIX))
.map(b => (this as any)[b] as EventBinding)
}
addBindings() {
this.bindings.forEach(binding => {
const [nodeOrEvent, event] = binding.name
if (nodeOrEvent === 'window' && event.length > 0) {
window.addEventListener(event, binding.binding.bind(this))
}
})
}
removeBindings() {
this.bindings.forEach(binding => {
const [nodeOrEvent, event] = binding.name
if (nodeOrEvent === 'window' && event) {
window.removeEventListener(event, binding.binding.bind(this))
}
})
}
}
}
}
当我调用时.removeBindings()
,函数运行window.removeEventListener
。但是,绑定实际上永远不会从窗口中删除。是什么导致这种情况发生?
以下是所有这些的调用方式:
@GameObject({})
class Player {
@AddEvent('window:click')
windowClick() {
console.log('here');
}
}
const player = new Player();
setTimeout(() => {
(player as any).removeBindings();
}, 5000);
每次.bind
执行函数时,都会创建一个新函数。
removeEventListener
仅当处理程序与===
传递给的处理程序相同 ( )时才有效addEventListener
。
function foo() {}
const bound1 = foo.bind();
const bound2 = foo.bind();
// not the same
console.log(bound1 === bound2);
您需要保存对绑定函数的引用,类似于
type AddedBindings = { eventName: string, fn: (...args: unknown[]) => unknown }[];
export function GameObject(options?: object) {
return function <T extends { new(...args: any[]): object }>(constructor: T) {
return class extends constructor {
private addedBindings: AddedBindings = [];
addBindings() {
const addedBindings: AddedBindings = [];
this.bindings.forEach(binding => {
const [nodeOrEvent, eventName] = binding.name
if (nodeOrEvent === 'window' && eventName.length > 0) {
const fn = binding.binding.bind(this);
addedBindings.push({ eventName, fn });
window.addEventListener(eventName, fn)
}
});
this.addedBindings = addedBindings;
}
removeBindings() {
this.addedBindings.forEach(({ eventName, fn }) => {
window.removeEventListener(eventName, fn);
});
}
另一个可能简化类型的选项是持久保存删除绑定的函数,而不是将事件名称和处理程序保存在属性中。
addBindings() {
const addedBindings = this.bindings
.filter(({ name: [nodeOrEvent, eventName] }) => nodeOrEvent === 'window' && eventName.length > 0)
.map((binding) => {
const fn = binding.binding.bind(this);
const eventName = binding[1];
window.addEventListener(eventName, fn)
return { eventName, fn };
});
this.removeAllBindings = () => {
for (const { eventName, fn } of addedBindings) {
window.removeEventListener(eventName, fn);
}
};
}
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句