如何删除事件处理程序的绑定版本?
How does one remove the bound version of an event handler?
我的绑定事件有问题,我想在触发更改事件时删除每个事件。没有循环它工作正常。
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
this.test = this.fontFamilyHandler.bind(this, el.getAttribute('id'));
el.addEventListener('change', this.test);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', this.test);
})
});
fontFamilyHandler = (key, evt) => {
this.objectInstance.set(key, evt.target.value);
this.canvas.requestRenderAll();
}
你知道为什么它不起作用吗?
在每次迭代中,您都会用下一个侦听器覆盖 this.test
。所以最后,this.test
将包含 附加的最后一个侦听器 ,因此它只能删除那个。
我可以在这里看到两个解决方案:
- 您可以保存 所有 监听器函数,然后再次删除它们,将元素映射到监听器:
this.objectInstance.on('selected', () => {
this.test = new WeakMap();
document.querySelectorAll('select').forEach((el) => {
const handler = this.fontFamilyHandler.bind(this, el.getAttribute('id'));
this.test.set(el, handler);
el.addEventListener('change', handler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
if (!this.test.has(el)) continue;
el.removeEventListener('change', this.test.get(el));
})
});
(注意:仅使用数组并不稳定,因为如果文档中 <select>
个元素的数量发生变化,索引将不同步。)
(注意:它也适用于 Map
而不是 WeakMap
,但后者允许更早地对从 [=55 中删除的任何 <select>
元素进行垃圾回收=].)
- 对所有元素使用相同的函数,而不是每次都绑定。由于您访问的是与监听器相同的元素,它是一个
<select>
,这意味着 change
事件只会来自 <select>
本身,因为它不能有任何子元素能够发送 change
事件,使用 event.target.id
也可以:
const eventHandler = event => this.fontFamilyHandler(event.target.id, event);
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
el.addEventListener('change', eventHandler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', eventHandler);
})
});
(注意:el.id
比 el.getAttribute('id')
更容易,而且效果相同 - 参见 Element#id
。)
- 或者,您可以直接使用
fontFamilyHandler
并将其更改为从元素本身读取 ID。
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
el.addEventListener('change', this.fontFamilyHandler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', this.fontFamilyHandler);
})
});
// I removed the `key` argument here
this.fontFamilyHandler = evt => {
this.objectInstance.set(evt.target.id, evt.target.value);
this.canvas.requestRenderAll();
}
从上面的评论...
"One needs to see surrounding code in order to get an understanding of the actual this
the OP is dealing with ... I'm especially curious about fontFamilyHandler = (key, evt) => { /* ... */ }
where this function floats freely versus line 3 where all of a sudden one sees this.fontFamilyHandler.bind(this, el.getAttribute('id'));
"
在那之前,下一个提供的答案假定了一种 class syntax/system 的假设 MyType
class.
当然是因为绑定...
this.fontFamilyHandler.bind(this, el.getAttribute('id'));
... 根本没有必要,因为 OP 已经访问了此处理程序中的 event.target
,它等于上面的 el
...
fontFamilyHandler = (key, evt) => {
this.objectInstance.set(key, evt.target.value);
this.canvas.requestRenderAll();
}
因此,绑定每个元素的 id
是不必要的,因为这个 属性 可以通过 evt.target.id
访问,就像已经通过 evt.target.value
.[=23 访问的值一样多=]
最后,代码将归结为更具可读性的内容,例如...
//class MyType {
// constructor() {
// this.objectInstance = { on: () => {} };
this.objectInstance.on('selected', () => document
.querySelectorAll('select')
.forEach(el =>
el.addEventListener('change', this.fontFamilyHandler)
)
);
this.objectInstance.on('deselected', () => document
.querySelectorAll('select')
.forEach(el =>
el.removeEventListener('change', this.fontFamilyHandler)
)
);
this.fontFamilyHandler = ({ target }) => {
this.objectInstance.set(target.id, target.value);
this.canvas.requestRenderAll();
};
// }
//}
我的绑定事件有问题,我想在触发更改事件时删除每个事件。没有循环它工作正常。
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
this.test = this.fontFamilyHandler.bind(this, el.getAttribute('id'));
el.addEventListener('change', this.test);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', this.test);
})
});
fontFamilyHandler = (key, evt) => {
this.objectInstance.set(key, evt.target.value);
this.canvas.requestRenderAll();
}
你知道为什么它不起作用吗?
在每次迭代中,您都会用下一个侦听器覆盖 this.test
。所以最后,this.test
将包含 附加的最后一个侦听器 ,因此它只能删除那个。
我可以在这里看到两个解决方案:
- 您可以保存 所有 监听器函数,然后再次删除它们,将元素映射到监听器:
this.objectInstance.on('selected', () => {
this.test = new WeakMap();
document.querySelectorAll('select').forEach((el) => {
const handler = this.fontFamilyHandler.bind(this, el.getAttribute('id'));
this.test.set(el, handler);
el.addEventListener('change', handler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
if (!this.test.has(el)) continue;
el.removeEventListener('change', this.test.get(el));
})
});
(注意:仅使用数组并不稳定,因为如果文档中 <select>
个元素的数量发生变化,索引将不同步。)
(注意:它也适用于 Map
而不是 WeakMap
,但后者允许更早地对从 [=55 中删除的任何 <select>
元素进行垃圾回收=].)
- 对所有元素使用相同的函数,而不是每次都绑定。由于您访问的是与监听器相同的元素,它是一个
<select>
,这意味着change
事件只会来自<select>
本身,因为它不能有任何子元素能够发送change
事件,使用event.target.id
也可以:
const eventHandler = event => this.fontFamilyHandler(event.target.id, event);
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
el.addEventListener('change', eventHandler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', eventHandler);
})
});
(注意:el.id
比 el.getAttribute('id')
更容易,而且效果相同 - 参见 Element#id
。)
- 或者,您可以直接使用
fontFamilyHandler
并将其更改为从元素本身读取 ID。
this.objectInstance.on('selected', () => {
document.querySelectorAll('select').forEach((el) => {
el.addEventListener('change', this.fontFamilyHandler);
})
});
this.objectInstance.on('deselected', () => {
document.querySelectorAll('select').forEach((el) => {
el.removeEventListener('change', this.fontFamilyHandler);
})
});
// I removed the `key` argument here
this.fontFamilyHandler = evt => {
this.objectInstance.set(evt.target.id, evt.target.value);
this.canvas.requestRenderAll();
}
从上面的评论...
"One needs to see surrounding code in order to get an understanding of the actual
this
the OP is dealing with ... I'm especially curious aboutfontFamilyHandler = (key, evt) => { /* ... */ }
where this function floats freely versus line 3 where all of a sudden one seesthis.fontFamilyHandler.bind(this, el.getAttribute('id'));
"
在那之前,下一个提供的答案假定了一种 class syntax/system 的假设 MyType
class.
当然是因为绑定...
this.fontFamilyHandler.bind(this, el.getAttribute('id'));
... 根本没有必要,因为 OP 已经访问了此处理程序中的 event.target
,它等于上面的 el
...
fontFamilyHandler = (key, evt) => {
this.objectInstance.set(key, evt.target.value);
this.canvas.requestRenderAll();
}
因此,绑定每个元素的 id
是不必要的,因为这个 属性 可以通过 evt.target.id
访问,就像已经通过 evt.target.value
.[=23 访问的值一样多=]
最后,代码将归结为更具可读性的内容,例如...
//class MyType {
// constructor() {
// this.objectInstance = { on: () => {} };
this.objectInstance.on('selected', () => document
.querySelectorAll('select')
.forEach(el =>
el.addEventListener('change', this.fontFamilyHandler)
)
);
this.objectInstance.on('deselected', () => document
.querySelectorAll('select')
.forEach(el =>
el.removeEventListener('change', this.fontFamilyHandler)
)
);
this.fontFamilyHandler = ({ target }) => {
this.objectInstance.set(target.id, target.value);
this.canvas.requestRenderAll();
};
// }
//}