RemoveEventListener不适合接触和鼠标侦听器

发布于 2025-01-21 14:50:28 字数 3509 浏览 2 评论 0原文

我参加了一堂课,以跟踪不同的事件侦听器,以便使元素更容易,更简化地从元素中添加和删除事件侦听器。删除了该类的版本:

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);
    }
}

我还有一个较小的类,用于以正确的格式生成侦听器,以与elementListenerstate类一起使用:

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);
    }
}

该功能在添加和删除大多数事件的听众时都与两个类别的预期工作,但是如果事件侦听器类型是“ MouseUp”或“ TouchEnd”,从CurrentListeners数组中删除了侦听器,但实际上并未从DOM元素中删除。当使用removePrevlisteners方法和removelistEnertype事件时,此问题就会发生。

由于我代码中的所有触摸端和鼠标事件都在删除ElementListEnsteNertate对象中的其他事件侦听器,但是Chrome Dev工具显示这些事件仍然附加了错误,因此没有任何错误打印到控制台上。

在这两种方法中,该函数均来自侦听器的回调属性,因此该函数应该是在AddListener中应用的确切函数,而不是副本。

我不确定问题来自何处,或者为什么仅在MouseUp中发生并接触到事件。有人有洞察力吗?

为了清楚起见,应用鼠标up并在我的代码中触摸事件时,我没有指定任何ARG,但这不是一个问题,因为我对某些Mousemove和TouchMove事件进行了相同的操作,这些事件确实可以通过removelistEnertype方法正确地删除。

I've made a class to keep track of differet event listeners in order to make dynamically adding and removing event listeners from an element easier and more streamlined. Stripped down version of the 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);
    }
}

I also have a smaller class for generating listeners in the correct format to work with the 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);
    }
}

The functionality works exactly as expected for both classes when adding and removing MOST event listeners, but if the event listener type is "mouseup" or "touchend", the ListenerObject gets removed from the currentListeners array but does not actually get removed from the DOM element. This issue happens when using the removePrevListeners method and the removeListenerType event.

No error gets printed to the console since all the touchend and mouseup events in my code are doing is removing other event listeners from an ElementListenerState object, but the chrome dev tools show that these events are still attached.

In both methods, the function comes from the callback property of a ListenerObject, so the function should be the exact function that was applied in addListener and not a copy.

I'm not exactly sure where the issue is coming from or why it's only happening with mouseup and touchend events. Anyone have some insight?

For clarity, when applying the mouseup and touchend events in my code I am not specifying any args, but this shouldn't be an issue since I've done the same with some mousemove and touchmove events which do get properly removed by the removeListenerType method.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

海螺姑娘 2025-01-28 14:50:28

在关闭之前回答我自己的问题:事实证明,问题与事件类型无关,而是一种不好的拼接方法。在我的removelistenertype方法中,我有逻辑可以从注册列表的副本中删除发现的侦听器,然后将列表设置为已更新的注册侦听器。我以某种方式忘记了将第二个参数添加到剪接方法中,无意中删除了在发现的侦听器之后出现的任何阵列中出现的任何内容,以防止删除Prevlevlisteners或RemovelisTenerType在下一个呼叫上正常工作。尴尬的错误,但我想这会发生。

Answering my own question before closing: As it turns out the issue has nothing to do with the event type, but rather a bad splice method. In my removeListenerType method I have logic to remove found listeners from the copy of the registered list before setting the list to the updated registered listeners. I somehow forgot to add the second parameter to the splice method, unintentionally removing anything in the array that appears AFTER the found listener, preventing removePrevListeners or removeListenerType from working properly on the next call. Embarassing mistake but I guess it happens.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文