4

我有一个事件监听器,它被分配给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 链接

我希望有人能解释我的错误,因为随着我的脚本变得更加复杂,它变得难以理解!

4

2 回答 2

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

b1并且b2不同的功能。

为了使您的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

于 2013-07-16T05:54:19.577 回答
0

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

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

于 2013-07-16T05:59:25.107 回答