removeEventListener 不适用于 touchend 和 mouseup 侦听器

removeEventListener does not work for touchend and mouseup listeners

我制作了一个 class 来跟踪不同的事件侦听器,以便更轻松、更流畅地动态添加和删除元素中的事件侦听器。 class:

的精简版
class ElementListenerState {
    /**
     * @param {object} element - pass DOM element to track listeners for (required)
     * @param {[object]} initialListeners - Initial list of Listeners to register (optional)
     * @returns
     */
    constructor(element, initialListeners = []) {
        this.element = element;
        this.currentListeners = initialListeners || [];
    }
    /**
     *
     * @returns {[]} a copy array of currentListeners
     */
    getCurrentListeners() {
        return [...this.currentListeners];
    }

    setCurrentListeners(arr) {
        this.currentListeners = arr;
    }

    removePrevListeners() {
        const prevListeners = this.getCurrentListeners();
        prevListeners.forEach((listener) => {
            this.element.removeEventListener(
                listener.eventType,
                listener.callback
            );
        });
        this.setCurrentListeners([]);
    }

    removeListenerType(type) {
        const currentListeners = this.getCurrentListeners();
        const listenersToRemove = currentListeners.filter(
            (listener) => listener.eventType === type
        );
        // if(!listenersToRemove.length) console.warn(`No listeners with type ${type} found.`)
        listenersToRemove.forEach((listener) => {
            this.element.removeEventListener(
                listener.eventType,
                listener.callback
            );
            currentListeners.splice(
                currentListeners.findIndex((listenerInArr) =>
                    listenerInArr === listener
                )
            );
        });
        this.setCurrentListeners(currentListeners);
    }

    /**
     *
     * @param {object} listener
     * @returns Error code -1 will be returned if listener is already registered, nothing will be returned if method was successful.
     */
    addListener(listener) {
        // Return error code if listener already registered in list
        if (this.getCurrentListeners().includes(listener)) {
            console.warn("Provided listener is already registered in list!");
            return -1;
        }
        this.element.addEventListener(listener.eventType, listener.callback);
        const newListeners = this.getCurrentListeners();
        newListeners.push(listener);
        this.setCurrentListeners(newListeners);
    }
}

我还有一个较小的 class 用于以正确的格式生成侦听器以使用 ElementListenerState class:

class ListenerObject {
    /**
     *
     * @param {string} eventType represents the type of event listener
     * @param {function} handler callback function for event listener
     * @param {[]} args Array of arguments (in proper order) for callback function, defaults to empty array
     */
    constructor(eventType, handler, args = []) {
        this.eventType = eventType;
        this.callback = (e) => handler(e, ...args);
    }
}

在添加和删除 MOST 事件侦听器时,classes 的功能完全符合预期,但如果事件侦听器类型是“mouseup”或“touchend”,ListenerObject 将从 currentListeners 数组中删除但实际上并没有从 DOM 元素中删除。使用 removePrevListeners 方法和 removeListenerType 事件时会发生此问题。

没有错误打印到控制台,因为我代码中的所有 touchend 和 mouseup 事件正在做的是从 ElementListenerState 对象中删除其他事件侦听器,但 chrome 开发工具显示这些事件仍然附加.

在这两种方法中,函数都来自 ListenerObject 的回调 属性,因此该函数应该是在 addListener 中应用的函数,而不是副本。

我不确定问题出在哪里或者为什么它只发生在 mouseup 和 touchend 事件上。任何人都有一些见解?

为清楚起见,在我的代码中应用 mouseup 和 touchend 事件时,我没有指定任何参数,但这应该不是问题,因为我已经对一些确实正确获取的 mousemove 和 touchmove 事件做了同样的事情通过 removeListenerType 方法移除。

关闭前回答我自己的问题:事实证明问题与事件类型无关,而是拼接方法错误。在我的 removeListenerType 方法中,我有逻辑在将列表设置为更新的注册侦听器之前从已注册列表的副本中删除找到的侦听器。我不知何故忘记将第二个参数添加到 splice 方法,无意中删除了数组中出现在找到的侦听器之后的任何内容,从而阻止 removePrevListeners 或 removeListenerType 在下一次调用时正常工作。令人尴尬的错误,但我想它会发生。