205

我想删除使用添加的特定类型的所有事件侦听器addEventListener()。我看到的所有资源都在说你需要这样做:

elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown',specific_function);

但我希望能够在不知道它当前是什么的情况下清除它,如下所示:

elem.addEventListener('mousedown',specific_function);
elem.removeEventListener('mousedown');
4

12 回答 12

268

addEventListener不幸的是,如果不拦截呼叫并跟踪侦听器或使用允许此类功能的库,这是不可能的。如果 listeners 集合是可访问的,但该功能没有实现,那将会是这样。

您可以做的最接近的事情是通过克隆元素来删除所有侦听器,这不会克隆侦听器集合。

注意:这也将删除元素子级的侦听器。

var el = document.getElementById('el-id'),
    elClone = el.cloneNode(true);

el.parentNode.replaceChild(elClone, el);
于 2013-10-19T19:47:21.717 回答
86

如果删除侦听器的唯一目标是阻止它们运行,则可以将事件侦听器添加到窗口捕获并取消给定类型的所有事件:

window.addEventListener(type, function(event) {
    event.stopImmediatePropagation();
}, true);

传入true第三个参数会导致事件在下降过程中被捕获。停止传播意味着事件永远不会到达正在侦听它的侦听器。

请记住,尽管这用途非常有限,因为您无法为给定类型添加新的侦听器(它们都将被阻止)。有一些方法可以在一定程度上解决这个问题,例如,通过触发一种只有您的听众会知道要收听的新事件。您可以这样做:

window.addEventListener('click', function (event) {
    // (note: not cross-browser)
    var event2 = new CustomEvent('click2', {detail: {original: event}});
    event.target.dispatchEvent(event2);
    event.stopPropagation();
}, true);

element.addEventListener('click2', function(event) {
    if (event.detail && event.detail.original) {
        event = event.detail.original
    }
    // Do something with event
});

但是,请注意,这可能不适用于诸如 mousemove 之类的快速事件,因为重新调度事件会引入延迟。

如果您需要这样做,最好只跟踪最初添加的听众,如 Martin Wantke 的回答中所述。

于 2017-10-28T06:28:35.657 回答
19

您必须重写 EventTarget.prototype.addEventListener 以构建一个陷阱函数来记录所有“添加侦听器”调用。像这样的东西:

var _listeners = [];

EventTarget.prototype.addEventListenerBase = EventTarget.prototype.addEventListener;
EventTarget.prototype.addEventListener = function(type, listener)
{
    _listeners.push({target: this, type: type, listener: listener});
    this.addEventListenerBase(type, listener);
};

然后你可以构建一个EventTarget.prototype.removeEventListener :

EventTarget.prototype.removeEventListeners = function(targetType)
{
    for(var index = 0; index != _listeners.length; index++)
    {
        var item = _listeners[index];

        var target = item.target;
        var type = item.type;
        var listener = item.listener;

        if(target == this && type == targetType)
        {
            this.removeEventListener(type, listener);
        }
    }
}

在 ES6 中,您可以使用 Symbol,将原始函数和所有添加的侦听器的列表直接隐藏在实例化对象自身中。

(function()
{
    let target = EventTarget.prototype;
    let functionName = 'addEventListener';
    let func = target[functionName];

    let symbolHidden = Symbol('hidden');

    function hidden(instance)
    {
        if(instance[symbolHidden] === undefined)
        {
            let area = {};
            instance[symbolHidden] = area;
            return area;
        }

        return instance[symbolHidden];
    }

    function listenersFrom(instance)
    {
        let area = hidden(instance);
        if(!area.listeners) { area.listeners = []; }
        return area.listeners;
    }

    target[functionName] = function(type, listener)
    {
        let listeners = listenersFrom(this);

        listeners.push({ type, listener });

        func.apply(this, [type, listener]);
    };

    target['removeEventListeners'] = function(targetType)
    {
        let self = this;

        let listeners = listenersFrom(this);
        let removed = [];

        listeners.forEach(item =>
        {
            let type = item.type;
            let listener = item.listener;

            if(type == targetType)
            {
                self.removeEventListener(type, listener);
            }
        });
    };
})();

你可以用这个小snipper来测试这段代码:

document.addEventListener("DOMContentLoaded", event => { console.log('event 1'); });
document.addEventListener("DOMContentLoaded", event => { console.log('event 2'); });
document.addEventListener("click", event => { console.log('click event'); });

document.dispatchEvent(new Event('DOMContentLoaded'));
document.removeEventListeners('DOMContentLoaded');
document.dispatchEvent(new Event('DOMContentLoaded'));
// click event still works, just do a click in the browser
于 2017-11-05T00:39:21.320 回答
14

删除全局事件的所有侦听器

element.onmousedown = null;

现在您可以返回通过添加事件侦听器

element.addEventListener('mousedown', handler, ...);

此解决方案仅适用于“全局”事件。自定义事件不起作用。这是所有全球事件的列表:https ://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers

于 2020-09-14T19:48:45.133 回答
9

我知道这是旧的,但我有一个没有真正答案的类似问题,我想keydown从文档中删除所有事件侦听器。我没有删除它们,而是在addEventListener添加它们之前覆盖它们以忽略它们,类似于上面的汤姆斯回答,通过在加载任何其他脚本之前添加它:

<script type="text/javascript">
    var current = document.addEventListener;
    document.addEventListener = function (type, listener) {
        if(type =="keydown")
        {
            //do nothing
        }
        else
        {
            var args = [];
            args[0] = type;
            args[1] = listener;
            current.apply(this, args);
        }
    };
</script>
于 2017-07-18T18:00:08.187 回答
4

所以这个函数摆脱了元素上大部分指定的侦听器类型:

function removeListenersFromElement(element, listenerType){
  const listeners = getEventListeners(element)[listenerType];
  let l = listeners.length;
  for(let i = l-1; i >=0; i--){
    removeEventListener(listenerType, listeners[i].listener);
  }
 }

有一些罕见的例外情况,由于某种原因无法删除。

于 2020-04-16T19:08:15.850 回答
3

在不引用原始函数的情况下删除事件侦听器的一种现代方法是使用AbortController。需要注意的是,您只能中止您自己添加的侦听器。

const buttonOne = document.querySelector('#button-one');
const buttonTwo = document.querySelector('#button-two');
const abortController = new AbortController();

// Add multiple click event listeners to button one
buttonOne.addEventListener(
  'click',
  () => alert('First'),
  { signal: abortController.signal }
);

buttonOne.addEventListener(
  'click',
  () => alert('Second'),
  { signal: abortController.signal }
);

// Add listener to remove first button's listeners
buttonTwo.addEventListener(
  'click',
  () => abortController.abort()
);
<p>The first button will fire two alert dialogs when clicked. Click the second button to remove those listeners from the first button.</p>

<button type="button" id="button-one">Click for alerts</button>
<button type="button" id="button-two">Remove listeners</button>

于 2021-09-17T14:25:27.007 回答
3

在不知道哪个回调附加到窗口侦听器的极端情况下,处理程序可以包装窗口,并且变量可以存储任何侦听器以通过例如addEventListener正确删除每个侦听器。removeAllEventListener('scroll')

var listeners = {};

var originalEventListener = window.addEventListener;
window.addEventListener = function(type, fn, options) {
    if (!listeners[type])
        listeners[type] = [];

    listeners[type].push(fn);
    return originalEventListener(type, fn, options);
}

var removeAllEventListener = function(type) {
    if (!listeners[type] || !listeners[type].length)
        return;

    for (let i = 0; i < listeners[type].length; i++)
        window.removeEventListener(type, listeners[type][i]);
}
于 2018-04-09T13:55:37.517 回答
3

通过一个 js 行删除元素中的所有侦听器:

element.parentNode.innerHTML += '';
于 2017-01-17T20:59:57.593 回答
2

您不能删除单个事件,但全部?立刻?做就是了

document.body.innerHTML = document.body.innerHTML

于 2019-09-26T17:50:12.670 回答
1

您也可以覆盖 'yourElement.addEventListener()' 方法并使用 '.apply()' 方法像往常一样执行侦听器,但在过程中拦截函数。喜欢:

<script type="text/javascript">

    var args = [];
    var orginalAddEvent = yourElement.addEventListener;

    yourElement.addEventListener = function() {
        //console.log(arguments);
        args[args.length] = arguments[0];
        args[args.length] = arguments[1];
        orginalAddEvent.apply(this, arguments);
    };

    function removeListeners() {
        for(var n=0;n<args.length;n+=2) {
            yourElement.removeEventListener(args[n], args[n+1]);
        }
    }

    removeListeners();

</script>

此脚本必须在页面加载时运行,否则它可能不会拦截所有事件侦听器。

确保在使用前删除“removeListeners()”调用。

于 2016-05-29T02:45:40.930 回答
0
 var events = [event_1, event_2,event_3]  // your events

//make a for loop of your events and remove them all in a single instance

 for (let i in events){
    canvas_1.removeEventListener("mousedown", events[i], false)
}
于 2018-12-28T09:47:47.390 回答