addEventListener vs onclick

Qual é a diferença entre addEventListener e onclick ?

 var h = document.getElementById("a"); h.onclick = dothing1; h.addEventListener("click", dothing2); 

O código acima reside em um arquivo .js separado e ambos funcionam perfeitamente.

Ambos estão corretos, mas nenhum deles é “melhor” por si só, e pode haver uma razão pela qual o desenvolvedor escolheu usar ambas as abordagens.

Ouvintes de events (addEventListener e attachEvent do IE)

Versões anteriores do Internet Explorer implementam o javascript de maneira diferente de praticamente qualquer outro navegador. Com versões menores que 9, você usa o attachEvent [ doc ], assim:

 element.attachEvent('onclick', function() { /* do stuff here*/ }); 

Na maioria dos outros navegadores (incluindo o IE 9 e acima), você usa addEventListener [ doc ], assim:

 element.addEventListener('click', function() { /* do stuff here*/ }, false); 

Usando essa abordagem ( events DOM Nível 2 ), você pode append um número teoricamente ilimitado de events a qualquer elemento único. A única limitação prática é a memory do lado do cliente e outras questões de desempenho, que são diferentes para cada navegador.

Os exemplos acima representam o uso de uma function anônima [ doc ]. Você também pode adicionar um ouvinte de evento usando uma referência de function [ doc ] ou um fechamento [ doc ]:

 var myFunctionReference = function() { /* do stuff here*/ } element.attachEvent('onclick', myFunctionReference); element.addEventListener('click', myFunctionReference , false); 

Outra característica importante de addEventListener é o parâmetro final, que controla como o listener reage aos events de borbulhamento [ doc ]. Eu tenho passado falso nos exemplos, que é padrão para provavelmente 95% dos casos de uso. Não há argumento equivalente para attachEvent ou ao usar events in-line.

Eventos in-line (propriedade onclick = “HTML” e “element.onclick”)

Em todos os navegadores que suportam javascript, você pode colocar um ouvinte de evento em linha, ou seja, diretamente no código HTML. Você provavelmente já viu isso:

 Click me 

Os desenvolvedores mais experientes evitam esse método, mas o trabalho é feito; é simples e direto. Você não pode usar encerramentos ou funções anônimas aqui (embora o manipulador em si seja uma function anônima das classificações) e seu controle de escopo seja limitado.

O outro método que você mencionou:

 element.onclick = function () { /*do stuff here */ }; 

… é o equivalente do javascript embutido, exceto pelo fato de que você tem mais controle do escopo (já que está escrevendo um script em vez de HTML) e pode usar funções anônimas, referências de funções e / ou encerramentos.

A desvantagem significativa dos events in-line é que, diferentemente dos ouvintes de evento descritos acima, você pode ter apenas um evento in-line atribuído. Os events inline são armazenados como um atributo / propriedade do elemento [ doc ], o que significa que ele pode ser sobrescrito.

Usando o exemplo do HTML acima:

 var element = document.getElementById('testing'); element.onclick = function () { alert('did stuff #1'); }; element.onclick = function () { alert('did stuff #2'); }; 

… quando você clicou no elemento, você veria apenas “Fez o material # 2” – você substituiu o primeiro atribuído da propriedade onclick pelo segundo valor e também substituiu a propriedade onclick HTML embutida original. Confira aqui: http://jsfiddle.net/jpgah/ .

Qual é melhor?

A questão é uma questão de compatibilidade e necessidade do navegador. Você precisa atualmente append mais de um evento a um elemento? Você vai no futuro? As probabilidades são, você vai. attachEvent e addEventListener são necessários. Se não, um evento inline fará o truque.

O jQuery e outras estruturas de javascript encapsulam as diferentes implementações de navegador dos events do DOM nível 2 em modelos genéricos, para que você possa escrever código em conformidade com o navegador, sem precisar se preocupar com o histórico do IE como um rebelde. Mesmo código com jQuery, todo navegador cruzado e pronto para o rock:

 $(element).on('click', function () { /* do stuff */ }); 

Não corra para fora e comece uma estrutura apenas para esta uma coisa, though. Você pode facilmente criar seu próprio pequeno utilitário para cuidar dos navegadores mais antigos:

 function addEvent(element, evnt, funct){ if (element.attachEvent) return element.attachEvent('on'+evnt, funct); else return element.addEventListener(evnt, funct, false); } // example addEvent( document.getElementById('myElement'), 'click', function () { alert('hi!'); } ); 

Experimente: http://jsfiddle.net/bmArj/

Levando tudo isso em consideração, a menos que o script que você está vendo tenha levado em consideração as diferenças do navegador de alguma outra forma (no código não mostrado na sua pergunta), a parte usando addEventListener não funcionaria nas versões IE menores que 9.

Documentação e Leitura Relacionada

  • Especificação HTML W3, elemento Atributos do manipulador de events
  • element.addEventListener no MDN
  • element.attachEvent no MSDN
  • Jquery.on
  • blog quirksmode “Introdução aos Eventos”
  • Bibliotecas javascript hospedadas em CDN no Google

A diferença que você poderia ver se tivesse outras funções:

 var h = document.getElementById('a'); h.onclick = doThing_1; h.onclick = doThing_2; h.addEventListener('click', doThing_3); h.addEventListener('click', doThing_4); 

As funções 2, 3 e 4 funcionam, mas 1 não funciona. Isso ocorre porque addEventListener não sobrescreve os manipuladores de events existentes, enquanto onclick substitui todos os manipuladores de events onclick = fn existentes.

A outra diferença significativa, é claro, é que onclick sempre funcionará, enquanto addEventListener não funciona no Internet Explorer antes da versão 9. Você pode usar o análogo attachEvent (que possui uma syntax ligeiramente diferente) no IE <9.

Nesta resposta, descreverei os três methods de definição de manipuladores de events DOM.

element.addEventListener()

Exemplo de código:

 const element = document.querySelector('a'); element.addEventListener('click', event => event.preventDefault(), true); 
 Try clicking this link. 

Enquanto o onclick funciona em todos os navegadores, o addEventListener não funciona em versões anteriores do Internet Explorer, que usa attachEvent .

A desvantagem de onclick é que só pode haver um manipulador de events, enquanto os outros dois triggersrão todos os retornos de chamada registrados.

Até onde sei, o evento DOM “load” ainda funciona de forma muito limitada. Isso significa que ele só será triggersdo para o window object , images e elementos , por exemplo. O mesmo vale para a atribuição direta de onload . Não há diferença técnica entre esses dois. Provavelmente .onload = tem uma melhor disponibilidade de navegador cruzado.

No entanto, você não pode atribuir um load event a um elemento

ou ou algo parecido.

Se você não está muito preocupado com o suporte ao navegador, há uma maneira de religar a referência ‘this’ na function chamada pelo evento. Ele normalmente apontará para o elemento que gerou o evento quando a function é executada, o que nem sempre é o que você deseja. A parte complicada é, ao mesmo tempo, ser capaz de remover o mesmo ouvinte de evento, como mostrado neste exemplo: http://jsfiddle.net/roenbaeck/vBYu3/

 /* Testing that the function returned from bind is rereferenceable, such that it can be added and removed as an event listener. */ function MyImportantCalloutToYou(message, otherMessage) { // the following is necessary as calling bind again does // not return the same function, so instead we replace the // original function with the one bound to this instance this.swap = this.swap.bind(this); this.element = document.createElement('div'); this.element.addEventListener('click', this.swap, false); document.body.appendChild(this.element); } MyImportantCalloutToYou.prototype = { element: null, swap: function() { // now this function can be properly removed this.element.removeEventListener('click', this.swap, false); } } 

O código acima funciona bem no Chrome, e provavelmente há alguma dificuldade em tornar o “bind” compatível com outros navegadores.

O uso de manipuladores in-line é incompatível com a Política de segurança de conteúdo, portanto, a abordagem addEventListener é mais segura desse ponto de vista. É claro que você pode habilitar os manipuladores in unsafe-inline com unsafe-inline , mas, como o nome sugere, não é seguro, pois traz de volta toda a horda de explorações de JavaScript que o CSP impede.

Um detalhe ainda não foi notado: os navegadores de desktop modernos consideram que diferentes pressionamentos de botão são “cliques” para AddEventListener('click' e AddEventListener('click' onclick por padrão).

  • No Chrome 42 e IE11, onclick e AddEventListener clicam em cliques à esquerda e ao meio.
  • No Firefox 38, o onclick triggers apenas no clique esquerdo, mas o clique AddEventListener acionado nos cliques esquerdo, médio e direito.

Além disso, o comportamento do clique do meio é muito inconsistente nos navegadores quando cursores de rolagem estão envolvidos:

  • No Firefox, os events de clique do meio sempre são acionados.
  • No Chrome, eles não serão triggersdos se a meia-mídia abrir ou fechar um cursor de rolagem.
  • No IE, eles são triggersdos quando o cursor de rolagem fecha, mas não quando é aberto.

Também é importante notar que os events de “clique” para qualquer elemento HTML selecionável pelo teclado, como input também são triggersdos no espaço ou são input quando o elemento é selecionado.

Também deve ser possível estender o ouvinte prototipando-o (se tivermos uma referência a ele e não a uma function anônima) ou fazer com que o ‘onclick’ chame uma chamada para uma biblioteca de funções (uma function chamando outras funções)

gostar

  elm.onclick = myFunctionList function myFunctionList(){ myFunc1(); myFunc2(); } 

isso significa que nunca precisamos desbancar a chamada onclick apenas alterar a function myFunctionList () para fazer o que quisermos, mas isso nos deixa sem controle das fases de borbulhamento / captura, portanto, deve ser evitado para navegadores mais novos.

apenas no caso de alguém encontrar esta discussão no futuro …

Segundo a MDN , a diferença é a seguinte:

addEventListener:

O método EventTarget.addEventListener () adiciona o object compatível com EventListener especificado à lista de ouvintes de evento para o tipo de evento especificado no EventTarget no qual ele é chamado. O destino do evento pode ser um elemento em um documento, o próprio documento, uma janela ou qualquer outro object que ofereça suporte a events (como XMLHttpRequest).

onclick:

A propriedade onclick retorna o código do manipulador de events de clique no elemento atual. Ao usar o evento de clique para acionar uma ação, considere também adicionar essa mesma ação ao evento keydown, para permitir o uso dessa mesma ação por pessoas que não usam mouse ou canvas sensível ao toque. Sintaxe element.onclick = functionRef; onde functionRef é uma function – geralmente um nome de uma function declarada em outro lugar ou uma expressão de function. Consulte “Guia JavaScript: Funções” para detalhes.

Há também uma diferença de syntax em uso como você vê nos códigos abaixo:

addEventListener:

 // Function to change the content of t2 function modifyText() { var t2 = document.getElementById("t2"); if (t2.firstChild.nodeValue == "three") { t2.firstChild.nodeValue = "two"; } else { t2.firstChild.nodeValue = "three"; } } // add event listener to table var el = document.getElementById("outside"); el.addEventListener("click", modifyText, false); 

onclick:

 function initElement() { var p = document.getElementById("foo"); // NOTE: showAlert(); or showAlert(param); will NOT work here. // Must be a reference to a function name, not a function call. p.onclick = showAlert; }; function showAlert(event) { alert("onclick Event detected!"); } 

addEventListener permite definir vários manipuladores, mas não é suportado no IE8 ou inferior.

IE tem attachEvent , mas não é exatamente o mesmo.

Javascript tende a misturar tudo em objects e isso pode torná-lo confuso. Tudo em um é o caminho do JavaScript.

Essencialmente onclick é um atributo HTML. Por outro lado, addEventListener é um método no object DOM que representa um elemento HTML.

Em objects JavaScript, um método é meramente uma propriedade que tem uma function como um valor e que funciona contra o object ao qual está anexado (usando isso, por exemplo).

Em JavaScript, o elemento HTML representado pelo DOM terá seus atributos mapeados em suas propriedades.

É aqui que as pessoas ficam confusas porque o JavaScript combina tudo em um único contêiner ou espaço de nomes sem camada de indireção.

Em um layout OO normal (que pelo menos mescla o namespace de properties / methods) você poderia ter algo como:

 domElement.addEventListener // Object(Method) domElement.attributes.onload // Object(Property(Object(Property(String)))) 

Existem variações como se fosse possível usar um getter / setter para onload ou HashMap para atributos, mas, no final, é assim que fica. O JavaScript eliminou essa camada de indireção com a expectativa de saber o que é o que, entre outras coisas. Ele mesclou domElement e atributos juntos.

Salvo a compatibilidade, você deve, como prática recomendada, usar addEventListener. Como outras respostas falam sobre as diferenças a esse respeito, em vez das diferenças programáticas fundamentais, deixarei de lado isso. Essencialmente, em um mundo ideal você está realmente destinado apenas a usar * de HTML, mas em um mundo ainda mais ideal, você não deveria estar fazendo nada parecido com HTML.

Por que é dominante hoje? É mais rápido escrever, mais fácil de aprender e tende a funcionar.

O ponto inteiro do onload em HTML é dar access ao método ou funcionalidade addEventListener em primeiro lugar. Ao usá-lo no JS você está passando por HTML quando você poderia aplicá-lo diretamente.

Hipoteticamente, você pode criar seus próprios atributos:

 $('[myclick]').each(function(i, v) { v.addEventListener('click', function() { eval(v.myclick); // eval($(v).attr('myclick')); }); }); 

O que o JS faz com isso é um pouco diferente disso.

Você pode igualar a algo como (para cada elemento criado):

 element.addEventListener('click', function() { switch(typeof element.onclick) { case 'string':eval(element.onclick);break; case 'function':element.onclick();break; } }); 

Os detalhes reais da implementação provavelmente serão diferentes com uma série de variações sutis, tornando os dois ligeiramente diferentes em alguns casos, mas essa é a essência disso.

É indiscutivelmente um hack de compatibilidade que você pode fixar uma function a um atributo on, pois, por padrão, os atributos são todos strings.

Resumo:

  1. addEventListener pode adicionar vários events, enquanto que com onclick isso não pode ser feito.
  2. onclick pode ser adicionado como um atributo HTML , enquanto um addEventListener só pode ser adicionado em elementos .
  3. addEventListener pode pegar um terceiro argumento que pode parar a propagação do evento.

Ambos podem ser usados ​​para manipular events. No entanto, addEventListener deve ser a escolha preferida, pois pode fazer tudo que onclick faz e muito mais. Não use onclick line como atributos HTML, pois isso mistura o javascript e o HTML, o que é uma prática ruim. Isso torna o código menos sustentável.

O contexto referenciado pela palavra-chave 'this' em JavasSript é diferente.

olhe o seguinte código:

 < !DOCTYPE html>          

O que isso é realmente simples. quando você clica no botão, o botão será desativado automaticamente.

Primeiro, quando você tentar ligar os events dessa maneira button.onclick = function(), evento onclick será acionado clicando no botão, no entanto, o botão não será desativado porque não há binding explícita entre os events button.onclick e onclick manipulador. Se você depurar o object 'this' , verá que ele se refere ao object 'window' .

Em segundo lugar, se você comentar btnSubmit.onclick = disable(); e descomente //btnSubmit.addEventListener('click', disable, false); você pode ver que o botão está desabilitado porque dessa forma há binding explícita entre o evento button.onclick e o manipulador de events onclick. Se você depurar na function de desativação, poderá ver que 'this' se refere ao button control e não à window .

Isso é algo que eu não gosto sobre JavaScript, que é inconsistência. Btw, se você estiver usando jQuery ( $('#btnSubmit').on('click', disable); ), ele usa binding explícita.