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

时间:2014-09-30 18:11:23

标签: javascript oop events javascript-events addeventlistener

我使用面向对象的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的命名空间中的函数完全相同。我在这里做错了什么?

任何帮助都会很棒。非常感谢你。

1 个答案:

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