Remover todos os ouvintes de evento de tipo específico


155

Desejo remover todos os ouvintes de eventos de um tipo específico que foram adicionados usando addEventListener(). Todos os recursos que estou vendo estão dizendo que você precisa fazer isso:

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

Mas eu quero poder limpá-lo sem saber o que é atualmente, assim:

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

Respostas:


227

Isso não é possível sem interceptar addEventListenerchamadas e acompanhar os ouvintes ou usar uma biblioteca que permite esses recursos, infelizmente. Teria sido se a coleção de ouvintes estivesse acessível, mas o recurso não fosse implementado .

O mais próximo que você pode fazer é remover todos os ouvintes clonando o elemento, que não clonará a coleção de ouvintes.

Nota: Isso também removerá ouvintes nos filhos do elemento.

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

el.parentNode.replaceChild(elClone, el);

3
Acho que você está assumindo que o nó substituído (com ouvintes de eventos) será coletado como lixo. Você pode ter problemas estranhos, se esse não for o caso.
Re

3
Os elementos órfãos do @Reno e seus ouvintes devem ser coletados como lixo em todos os navegadores modernos. Obviamente, se você mantinha algumas referências ao nó DOM inicial em JS em algum lugar, precisará levar isso em consideração.
Plalx #

1
@ Heitor, windownão é um elemento DOM, portanto não.
Plalx 8/15/16

1
Outra coisa ruim é que ele quebrará as referências a esse nó.
N73k

1
@ user10089632 Não é possível com APIs JS nativas.
plalx

50

Se seu único objetivo, removendo os ouvintes, é impedi-los de executar, você pode adicionar um ouvinte de eventos à janela capturando e cancelando todos os eventos do tipo especificado:

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

Passar truepara o terceiro parâmetro faz com que o evento seja capturado no caminho para baixo. Interromper a propagação significa que o evento nunca atinge os ouvintes que estão ouvindo.


9
E se o evento estiver vinculado ao objeto de janela, como, por exemplo, no evento de mensagem?
22419 van_folmert

11

Você deve substituir EventTarget.prototype.addEventListener para criar uma função de interceptação para registrar todas as chamadas 'adicionar ouvinte'. Algo assim:

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

Em seguida, você pode criar um EventTarget.prototype.removeEventListener s :

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

No ES6, você pode usar um símbolo para ocultar a função original e a lista de todos os ouvintes adicionados diretamente no próprio objeto instanciado.

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

Você pode testar esse código com este pequeno 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

7

Sei que isso é antigo, mas tive um problema semelhante sem respostas reais, onde queria remover todos os ouvintes de evento "keydown" do documento. Em vez de removê-los, substituí o addEventListener para ignorá-los antes mesmo de serem adicionados, semelhante à resposta do Toms acima, adicionando-o antes que outros scripts sejam carregados .:

<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>

2
Você pode passar argumentos diretamente, type === 'keydown' || current.apply(this, arguments);seria uma linha legal. Você também pode agrupar tudo em um IIFE para evitar currentvazamento no escopo global.
Şafak Gür

3

No caso extremo de não saber qual retorno de chamada está anexado a um ouvinte de janela, um manipulador pode ser wrapper em torno da janela addEventListenere uma variável pode armazenar sempre ouvintes para remover adequadamente cada um deles por removeAllEventListener('scroll')exemplo.

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

2

Portanto, essa função se livra da maioria dos tipos de ouvintes especificados em um elemento:

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

Houve algumas exceções raras em que não é possível remover por algum motivo.


De longe a melhor resposta! Por que ninguém mencionou getEventListenersantes?
mamiu 16/04

2
Sinto muito, mas preciso retomar o que disse, getEventListenersestá funcionando apenas no ChromeDevTools na linha de comando, portanto, não é útil para quase nenhum caso. codepen.io/azaslavsky/pres/sybfE
mamiu 16/04

1

Como alternativa, você pode substituir o método 'yourElement.addEventListener ()' e usar o método '.apply ()' para executar o ouvinte normalmente, mas interceptando a função no processo. Gostar:

<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>

Esse script deve ser executado no carregamento da página ou pode não interceptar todos os ouvintes de eventos.

Certifique-se de remover a chamada 'removeListeners ()' antes de usar.


1

Remova todos os ouvintes no elemento por uma linha js :

element.parentNode.innerHTML += '';

Isso só funcionaria sem efeitos colaterais se o elemento fosse o único filho.
plalx

Há tambémelement.outerHTML = element.outerHTML
Jacksonkr

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

-1

Você não pode remover um único evento, mas tudo? de uma vez só? apenas faça

document.body.innerHTML = document.body.innerHTML


Eu não entendo por que isso foi rebaixado, o mais simples aqui
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.