首页 > 解决方案 > 无法删除 windows 对象的事件侦听器

问题描述

我在尝试删除事件侦听器时遇到了很多麻烦。

我创建了一个非常依赖 JavaScript 的网站。当您在网站上导航时,它基本上是动态加载元素,而无需使用模板文字刷新页面。

我有时必须加载内容并添加无限滚动,但也能够再次删除该事件。

这是我用来处理滚动事件的代码:

var start  = 30;
var active = true;

function yHandler(elem)
{

    var oHeight = selectElems('content_main', 'i').offsetHeight;
    var yOffset = window.pageYOffset;
    var hLimit  = yOffset + window.innerHeight;

    if (hLimit >= oHeight - 500 && active === true)
    {

        active = false;
        new requestContent({
            page: GET.page,
            type: returnContentType(GET.page),
            scroll: true,
            start: start
        }, (results) => {
            if(results){
                setTimeout(()=>{
                    active = true;
                    start  = start + 30;;
                }, 400);
                new ContentActive();
            }
        });
    }
}

var scrollRoute = 
    {

    contentScroll: () =>{
        yHandler();
    }
};

var scrollHandler = function(options)
{

    var func = options.func.name;
    var funcOptions = options.func.options;
    var elem = options.elem;
    var flag = options.flag;

    this.events = () => {
        addEvent(elem, 'scroll', ()=>{
            scrollRoute[func](elem, funcOptions);
        }, flag);
    }
    this.clear = () => {
        elem.removeEventListener('scroll', scrollRoute[func](), flag);
    }
}

我正在使用此功能来设置事件

function addEvent(obj, type, fn, flag = false) {
    if (obj.addEventListener) {
        obj.addEventListener(type, fn, flag);
    } else if (obj.attachEvent) {
        obj["e" + type + fn] = fn;
        obj[type + fn] = function () {
            obj["e" + type + fn](window.event);
        };
        obj.attachEvent("on" + type, obj[type + fn]);
    } else {
        obj["on" + type] = obj["e" + type + fn];
    }
}

当我需要设置无限滚动事件时,我从任何代码中调用此代码

new scrollHandler({
    func: {
        'name':'contentScroll',
    },
    elem: window,
    flag: true,
}).events();

当我需要删除无限滚动事件但没有任何运气时,我从任何代码中调用此代码

new scrollHandler({
    func: {
        'name':'contentScroll',
    },
    elem: window,
    flag: true,
}).clear();

如何成功删除事件监听器?我不能只命名实例,从长远来看,在从不同的地方设置和删除滚动事件时会很混乱。

标签: javascriptevent-listenerremoveeventlistener

解决方案


Two problems:

  1. You have to pass the same function to removeEventListener as you passed to addEventListener. (Similarly, you have to pass the same function to detachEvent as you passed to attachEvent using Microsoft's proprietary stuff — but unless you really have to support IE8 and earlier, you can ditch all that.) Your code isn't doing that.

  2. When trying to remove the handler, you're calling scrollRoute[func]() and passing its return value into removeEventListener. As far as I can tell, that's passing undefined into removeEventListener, which won't do anything useful.

Here's the code I'm referring to above:

this.events = () => {
    addEvent(elem, 'scroll', ()=>{               // *** Arrow function you don't
        scrollRoute[func](elem, funcOptions);    // *** save anywhere
    }, flag);                                    // ***
}
this.clear = () => {
    elem.removeEventListener('scroll', scrollRoute[func](), flag);
// Calling rather than passing func −−−^^^^^^^^^^^^^^^^^^^
}

Notice that the function you're passing addEvent (which will pass it to addEventListener) is an anonymous arrow function you don't save anywhere, but the function you're passing removeEventListener is the result of calling scrollRoute[func]().

You'll need to keep a reference to the function you pass addEvent and then pass that same function to a function that will undo what addEvent did (removeEvent, perhaps?). Or, again, ditch all that, don't support IE8, and use addEventListener directly.

So for instance:

var scrollHandler = function(options) {
    var func = options.func.name;
    var funcOptions = options.func.options;
    var elem = options.elem;
    var flag = options.flag;
    var handler = () => {
        scrollRoute[func](elem, funcOptions);
    };

    this.events = () => {
        elem.addEventListener('scroll', handler, flag);
    };
    this.clear = () => {
        elem.removeEventListener('scroll', handler, flag);
    };
};

(Notice I added a couple of missing semicolons, since you seem to be using them elsewhere, and consistent curly brace positioning.)

Or using more features of ES2015 (since you're using arrow functions already):

var scrollHandler = function(options) {
    const {elem, flag, func: {name, options}} = options;
    const handler = () => {
        scrollRoute[name](elem, options);
    };

    this.events = () => {
        elem.addEventListener('scroll', handler, flag);
    };
    this.clear = () => {
        elem.removeEventListener('scroll', handler, flag);
    };
};

推荐阅读