Javascript事件addEventListener为同一函数多次注册;使用OOP Javascript

Javascript event addEventListener registering multiple times for same function; using OOP Javascript

本文关键字:Javascript 注册 OOP 使用 函数 事件 addEventListener      更新时间:2023-09-26

我使用面向对象的Javascript,并注册事件侦听器。根据我对事件侦听器的了解,如果应用于eventtarget的函数已经注册,则重复尝试添加同一事件侦听器将被忽略。换句话说,它应该只发射一次。但在下面的代码中并非如此(也可以在jsfiddle上看到)。

https://developer.mozilla.org/en-US/docs/Web/API/EventTarget.addEventListener

多个相同的事件侦听器

如果在具有相同参数的同一EventTarget上注册了多个相同的EventListener,则会丢弃重复的实例。它们不会导致EventListener被调用两次,并且由于重复项被丢弃,因此不需要使用removeEventListener方法手动删除它们。

http://jsfiddle.net/qd1e8f6c/

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中的函数完全相同。我在这里做错了什么?

任何帮助都会很棒。

不能将同一类型/函数对绑定到一个元素。但是,这并不是您要做的,而是在每次调用namespace.addEventListener函数时显式地创建一个新的handler函数。

您所拥有的:

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);
    }
};

因为在第二种情况下只有CCD_ 6的一个实例。

名称间距

您所拥有的是一种名称调整方法,但现在最常见的是,JS名称调整是通过模块模式完成的

例如,对于您的情况,您似乎并不真正关心通过这个"命名空间"变量使您的代码全局可访问,因为它只在您的代码中使用,所以您可以这样做:

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
        }
    };
})();