无法删除事件监听器,不理解我的错误

时间:2013-07-16 05:21:46

标签: javascript

我有一个事件监听器,使用div监听器分配给click

问题是它不会删除它只是不断添加的侦听器。

这是发生这种情况的脚本:

var resourceCheckout = function (quantity,btn){
    //quantity = integer
    // btn = document.getElementByID('the_div');

    var calculate = function (e) {
        var allowed = false;
        for(var i in test){
            var total = quantity * test[i].q;                        
            if(total > 200){ //if total > 200 remove eventListener
                allowed = false; break;
            } else {
                allowed = true;
            }
        };    
        if(allowed){
            btn.addEventListener('click',assign,false);
        } else {
            btn.removeEventListener('click', assign ,false);
        }
    };
    var assign = function (e) {
        do_it(quantity); //this gets called more than once when it should be
        // a maximum of one
    };
    calculate();
};

我决定制作一个有效的 jsfiddle 来向你展示它,只需移动滑块然后按下按钮,然后它将调用侦听器所分配的功能并计算它被召唤的次数。

JSFIDDLE LINK

我希望有人可以解释我的错误,因为我的脚本变得更加复杂会让人感到困惑!

2 个答案:

答案 0 :(得分:4)

问题是您尝试删除的功能从未添加过,因此不会删除任何内容。

resourceCheckout功能的每次通话都会创建 assign功能,然后由calculate功能使用。由于它是 assign函数,因此无法将其添加到按钮中,因此调用removeEventListener并将其传入后无效。

如果先前对resourceCheckout的调用在按钮上放置assign,则必须使用相同的功能参考将其删除。

这可以通过一个更简单的例子来更清楚:

function foo() {
    function bar() {
    }

    return bar;
}

foo每次调用时都会创建一个新的 bar函数。所以:

var b1 = foo();
var b2 = foo();
console.log(b1 === b2); // false

b1b2不同的功能。

要使resourceCheckout正常工作,您需要记住之前的assign并使用它来移除处理程序。

您在评论中询问为什么这不适用于小提琴中的滑块代码,看起来像这样(因为它不在问题中):

// The OP's slider code
var initSlider = function (el,func,data) {
    var clickX = null;
    var startSlider = function (e) {
        clickX = e.pageX;
        document.body.addEventListener('mousemove', calc, false);
        document.body.addEventListener('mouseup', endSlider, false);
    };
    var endSlider = function (e) {
        document.body.removeEventListener('mousemove', calc, false);
        document.body.removeEventListener('mouseup', endSlider, false);
    };

    var calc = function (e) {
        var dif = e.pageX - clickX;
        clickX = e.pageX;
        var parentWidth = parseInt(window.getComputedStyle(el.parentNode).width);
        var childWidth = parseInt(window.getComputedStyle(el).width);
        var childLeft = parseInt(window.getComputedStyle(el).left);
        var left = childLeft + dif;

        if (left < 0) { left = 0; }
        else if (left > (parentWidth-childWidth)) { left = (parentWidth-childWidth); }

        el.style.left = left + 'px';
        func(data,left,parentWidth-childWidth);
    };
    el.addEventListener("mousedown", startSlider, false);
};

在那里,startSlider代码成功地从body元素中删除了一个处理程序。这是有效的,因为startSlider代码引用了endSlider函数,该函数是在创建startSlider的同时创建的(对initSlider的同一调用)。因此startSlider引用了addEventListener使用的相同函数,removeEventListener可以正常工作。

答案 1 :(得分:0)

此代码可能会在每次调用事件时为该事件添加一个新的侦听器。

另请注意,每次调用ResourceCheckout时,都会为变量assign创建一个新的不同函数对象,因此removeEventListener永远不会成功,因为刚刚创建了传递的特定函数对象并且从未注册过该事件(注册的是一个不同的函数对象,在之前的调用中创建)。