Obtenha ouvintes de eventos anexados ao nó usando addEventListener

106

Já olhei para estas questões:

entretanto, nenhum deles responde como obter uma lista de ouvintes de evento anexados a um nó usando addEventListener, sem modificar o addEventListenerprotótipo antes que os ouvintes de evento sejam criados.

VisualEvent não exibe todos os ouvintes de eventos (específicos do iphone) e eu quero fazer isso (um pouco) programaticamente.

Tyilo
fonte
"um tanto programaticamente" e o fato de que a resposta aceita para esta pergunta é um recurso do devtools torna esta uma duplicata da pergunta listada. Para quem procura uma solução JS, a resposta é "não existe nenhuma"
Nickolay

Respostas:

135

Chrome DevTools, Safari Inspector e Firebug são compatíveis com getEventListeners (nó) .

getEventListeners (documento)

NVI
fonte
6
Quero observar que o método getEventListeners não é compatível com a versão 35 do Firefox.
MURATSPLAT
Pode não funcionar no Firefox, mas, novamente, os desenvolvedores desenvolvem em vários navegadores / Isso AJUDA se for necessário modificar um site existente ... MUITO!
JasonXA
1
Não é o Firefox 69.
Vitaly Zdanevich
65

Você não pode.

A única maneira de obter uma lista de todos os ouvintes de eventos anexados a um nó é interceptar a chamada de anexo do ouvinte.

DOM4 addEventListener

Diz

Anexar um ouvinte de evento à lista associada de ouvintes de evento com tipo definido para tipo, ouvinte definido para ouvinte e captura definida para capturar, a menos que já haja um ouvinte de evento nessa lista com o mesmo tipo, ouvinte e captura.

O que significa que um ouvinte de evento é adicionado à "lista de ouvintes de evento". Isso é tudo. Não há noção do que esta lista deve ser nem como você deve acessá-la.

Raynos
fonte
12
Alguma chance de fornecer alguma justificativa ou raciocínio por que isso deve funcionar dessa maneira? Obviamente, o navegador sabe o que todos os ouvintes são.
Darth Egregious,
3
@ user973810: Como você quer que ele justifique isso? A API DOM não fornece nenhuma maneira de fazer isso e não há maneiras não padronizadas de fazer isso nos navegadores atuais. Quanto a por que isso acontece, eu realmente não sei. Parece uma coisa razoável a se querer fazer.
Tim Down,
Eu vi alguns tópicos por aí sobre como adicionar uma API ao DOM para isso.
Raynos,
@TimDown a edição ajuda. Ver que não há especificação para algo como "getEventListeners" justifica porque não existe tal coisa.
Darth Egregious,
24

Como não há uma maneira nativa de fazer isso, aqui está uma solução menos intrusiva que encontrei (não adicione nenhum método de protótipo 'antigo'):

var ListenerTracker=new function(){
    var is_active=false;
    // listener tracking datas
    var _elements_  =[];
    var _listeners_ =[];
    this.init=function(){
        if(!is_active){//avoid duplicate call
            intercep_events_listeners();
        }
        is_active=true;
    };
    // register individual element an returns its corresponding listeners
    var register_element=function(element){
        if(_elements_.indexOf(element)==-1){
            // NB : split by useCapture to make listener easier to find when removing
            var elt_listeners=[{/*useCapture=false*/},{/*useCapture=true*/}];
            _elements_.push(element);
            _listeners_.push(elt_listeners);
        }
        return _listeners_[_elements_.indexOf(element)];
    };
    var intercep_events_listeners = function(){
        // backup overrided methods
        var _super_={
            "addEventListener"      : HTMLElement.prototype.addEventListener,
            "removeEventListener"   : HTMLElement.prototype.removeEventListener
        };

        Element.prototype["addEventListener"]=function(type, listener, useCapture){
            var listeners=register_element(this);
            // add event before to avoid registering if an error is thrown
            _super_["addEventListener"].apply(this,arguments);
            // adapt to 'elt_listeners' index
            useCapture=useCapture?1:0;

            if(!listeners[useCapture][type])listeners[useCapture][type]=[];
            listeners[useCapture][type].push(listener);
        };
        Element.prototype["removeEventListener"]=function(type, listener, useCapture){
            var listeners=register_element(this);
            // add event before to avoid registering if an error is thrown
            _super_["removeEventListener"].apply(this,arguments);
            // adapt to 'elt_listeners' index
            useCapture=useCapture?1:0;
            if(!listeners[useCapture][type])return;
            var lid = listeners[useCapture][type].indexOf(listener);
            if(lid>-1)listeners[useCapture][type].splice(lid,1);
        };
        Element.prototype["getEventListeners"]=function(type){
            var listeners=register_element(this);
            // convert to listener datas list
            var result=[];
            for(var useCapture=0,list;list=listeners[useCapture];useCapture++){
                if(typeof(type)=="string"){// filtered by type
                    if(list[type]){
                        for(var id in list[type]){
                            result.push({"type":type,"listener":list[type][id],"useCapture":!!useCapture});
                        }
                    }
                }else{// all
                    for(var _type in list){
                        for(var id in list[_type]){
                            result.push({"type":_type,"listener":list[_type][id],"useCapture":!!useCapture});
                        }
                    }
                }
            }
            return result;
        };
    };
}();
ListenerTracker.init();
Yorg
fonte
Você também deve fazer com que ele intercepte ouvintes de eventos de janela. Fora isso, isso funciona muito bem!
2

Você pode obter todos os eventos jQuery usando $ ._ data ($ ('[selector]') [0], 'events'); mude [seletor] para o que você precisa.

Existe um plugin que reúne todos os eventos anexados por jQuery chamado eventsReport.

Também escrevo meu próprio plugin que faz isso com melhor formatação.

Mas de qualquer forma, parece que não podemos reunir eventos adicionados pelo método addEventListener. Pode ser que possamos encapsular a chamada addEventListener para armazenar eventos adicionados após nossa chamada.

Parece a melhor maneira de ver eventos adicionados a um elemento com ferramentas de desenvolvimento.

Mas você não verá eventos delegados lá. Então, precisamos do jQuery eventsReport.

ATUALIZAÇÃO: AGORA PODEMOS ver os eventos adicionados pelo método addEventListener VER A RESPOSTA CORRETA PARA ESTA PERGUNTA.

Rantiev
fonte
Esta é uma interface privada e obsoleta e pode desaparecer em breve, então não confie nela.
mgol
1
Sim, mas quando respondi, não existia essa capacidade nas ferramentas de desenvolvimento. Portanto, não havia nada para escolher.
Rantiev
O uso de @Rantiev está obsoleto, você pode remover essa resposta?
Julio Marins
2

Não consigo encontrar uma maneira de fazer isso com o código, mas no estoque do Firefox 64, os eventos são listados ao lado de cada entidade HTML no Inspetor de Ferramentas do Desenvolvedor, conforme observado na página Examinar Ouvintes de Eventos do MDN e conforme demonstrado nesta imagem:

captura de tela do FF Inspector

Adam Katz
fonte