我使用面向对象的Javascript,同时注册事件监听器。根据我对事件侦听器的理解,如果已经注册了应用于eventtarget的函数,则将忽略重复尝试添加此相同的事件侦听器。换句话说,它应该只发射一次。但在下面的代码中并非如此(也可以在jsfiddle上看到)。
https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener
多个相同的事件监听器
如果在具有相同参数的同一EventTarget上注册了多个相同的EventListener,则会丢弃重复的实例。它们不会导致EventListener被调用两次,并且由于重复项被丢弃,因此不需要使用removeEventListener方法手动删除它们。
HTML
<div id="wrapper">
<input id="t1" type="text" />
<input id="btn" type="button" />
</div>
JS
var namespace = namespace || {};
namespace.event = {
addListener: function(el, type) {
var handle = function() {
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
el.addEventListener(type, handle, false);
}
};
namespace.ExampleClass = function() {
this.init = function(el1, el2) {
el1.value = "123";
el2.value = "Click Me";
};
};
var textbox = document.getElementById("t1");
var button = document.getElementById("btn");
var inst = new namespace.ExampleClass();
inst.init( textbox, button );
namespace.event.addListener(textbox, "focus");
namespace.event.addListener(button, "click");
// same handle -- shoudln't it only add the event once?
namespace.event.addListener(textbox, "focus");
namespace.event.addListener(button, "click");
正如您在上面代码的最后几行中所看到的,一个名为addListener
的函数被执行两次,它将事件注册到每个输入。然后,再次执行addListener
。我希望它不会再次注册而忽略,但实际上它会注册。我不明白。名为handle
的命名空间中的函数完全相同。我在这里做错了什么?
任何帮助都会很棒。非常感谢你。
答案 0 :(得分:8)
您不能将相同的类型/功能对绑定到元素。但是,这不是您正在做的事情,您在每次调用handler
函数时明确创建一个新的namespace.addEventListener
函数。
你有什么:
namespace.event = {
addListener: function(el, type) {
var handle = function() {
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
el.addEventListener(type, handle, false);
}
};
你会期望做什么:
var handle = function(evt) {
var el = evt.currentTarget;
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
namespace.event = {
addListener: function(el, type) {
el.addEventListener(type, handle, false);
}
};
因为在第二种情况下只有handle
的一个实例。
你所拥有的是命名空间的一种方法,但最常见的是,JS命名空间是通过Module Pattern
完成的。对于您的情况,例如,您甚至似乎并不真正关心通过此“命名空间”变量全局访问您的代码,因为它仅在您的代码中使用,因此您可以这样做:
var namespace = (function(){
function handle(evt) {
var el = evt.currentTarget;
switch (type) {
case "focus":
console.log(el.value);
break;
case "click":
console.log(el.id + " was clicked");
break;
}
};
function addListener(el, type) {
el.addEventListener(type, handle, false);
}
function ExampleClass() {
this.init = function(el1, el2) {
el1.value = "123";
el2.value = "Click Me";
};
};
var textbox = document.getElementById("t1");
var button = document.getElementById("btn");
var inst = new ExampleClass();
inst.init( textbox, button );
addListener(textbox, "focus");
addListener(button, "click");
// And if you do care about 'inst' being global, you'd explicitly add it to the window.
window.inst = inst;
// Whatever functions you want to expose as 'namespace' would go here.
return {
event: {
addEventListener: addEventListener
}
};
})();