Vinculando vários eventos a um ouvinte (sem JQuery)?

144

Enquanto trabalhava com eventos do navegador, comecei a incorporar o touchEvents do Safari para dispositivos móveis. Acho que addEventListenerestão se acumulando com condicionais. Este projeto não pode usar o JQuery.

Um ouvinte de evento padrão:

/* option 1 */
window.addEventListener('mousemove', this.mouseMoveHandler, false);
window.addEventListener('touchmove', this.mouseMoveHandler, false);

/* option 2, only enables the required event */
var isTouchEnabled = window.Touch || false;
window.addEventListener(isTouchEnabled ? 'touchmove' : 'mousemove', this.mouseMoveHandler, false);

O JQuery's bindpermite vários eventos, como:

$(window).bind('mousemove touchmove', function(e) {
    //do something;
});

Existe uma maneira de combinar os dois ouvintes de eventos como no exemplo JQuery? ex:

window.addEventListener('mousemove touchmove', this.mouseMoveHandler, false);

Todas as sugestões ou dicas são bem-vindas!

johnkreitlow
fonte
@RobG provavelmente porque a pergunta é como replicar algumas das funcionalidades do jQuery. Não tenho certeza se esse é um uso apropriado para uma tag ou não.
Michael Martin-Smucker
Justo, parecia-me que a pergunta não precisava disso. Parece um pouco sarcástico, porém, excluído.
RobG

Respostas:

104

No POJS, você adiciona um ouvinte por vez. Não é comum adicionar o mesmo ouvinte para dois eventos diferentes no mesmo elemento. Você pode escrever sua própria função pequena para fazer o trabalho, por exemplo:

/* Add one or more listeners to an element
** @param {DOMElement} element - DOM element to add listeners to
** @param {string} eventNames - space separated list of event names, e.g. 'click change'
** @param {Function} listener - function to attach for each event as a listener
*/
function addListenerMulti(element, eventNames, listener) {
  var events = eventNames.split(' ');
  for (var i=0, iLen=events.length; i<iLen; i++) {
    element.addEventListener(events[i], listener, false);
  }
}

addListenerMulti(window, 'mousemove touchmove', function(){…});

Espero que isso mostre o conceito.

Editar 2016-02-25

O comentário de Dalgard me fez revisitar isso. Eu acho que adicionar o mesmo ouvinte para vários eventos em um elemento é mais comum agora para cobrir os vários tipos de interface em uso, e a resposta de Isaac oferece um bom uso de métodos internos para reduzir o código (embora menos código seja, por si só) , não necessariamente um bônus). Ampliado com as funções de seta do ECMAScript 2015, fornece:

function addListenerMulti(el, s, fn) {
  s.split(' ').forEach(e => el.addEventListener(e, fn, false));
}

Uma estratégia semelhante pode adicionar o mesmo ouvinte a vários elementos, mas a necessidade de fazer isso pode ser um indicador para a delegação de eventos.

RobG
fonte
4
Obrigado pela frase "It is not common to add the same listener for two different events on the same element."Às vezes (verdes) devs precisa ouvir isso de saber que eles estão fazendo certo :)
Ivan Durst
1
Você não quer dizer "não é incomum"?
21816 dalgard
2
@ dalgard - é mais comum agora que os dispositivos de toque são mais comuns, mas apenas para um número limitado de eventos (como mouse e touchmove). O fato de ser necessário mostra a falta de visão dos eventos de nomenclatura após itens físicos; o movimento do ponteiro pode ter sido mais apropriado. Pode ser implementado por toque ou outro dispositivo. Antes dos ratos (ou mouses), havia rodas x / y, algumas que eu usei tinham rodas de mão e pé (Stecometer dos anos 70). Existem também bolas e esferas de pista, algumas se movem em 3d.
RobG
2
@RobG: A API com a qual estou lidando é o DOM, e sim, suas deficiências são uma legião :) Mas também pode ser simplesmente uma questão de evitar código duplicado em ouvintes semelhantes.
28816 dalgard
1
@ PedroFerreira - sim, é claro, provavelmente mais da metade dos navegadores atualmente em uso não suporta funções de seta, mas eles são divertidos de brincar e sempre há Babel . ;-)
RobG 08/03
119

Alguma sintaxe compacta que alcança o resultado desejado, POJS:

   "mousemove touchmove".split(" ").forEach(function(e){
      window.addEventListener(e,mouseMoveHandler,false);
    });
Isaac
fonte
154
Ou diretamente['mousemove', 'touchmove'].forEach(...)
Dan Dascalescu 3/15/15
+1 E não precisa da extensão «ECMAScript 2015 arrow functions»! ;-)
Pedro Ferreira
@zuckerburg Para começar, em vez de codificar a matriz em que você codificou a sequência e a dividiu, você tem certeza de que esse é o caminho a seguir? Tem certeza de que esta é a maneira mais legível de escrever isso? ['mousemove', 'touchmove'].forEach(function(event) { window.addEventListener(event, handler);}); seria não apenas muito mais legível, mas também muito mais rápido, sem precisar dividir a sequência e executar uma função para cada item na matriz resultante.
Iharob Al Asimi
2
@IharobAlAsimi este código foi escrito há mais de 4 anos, encontrei minha barra de espaço nesse período. A divisão da cadeia de caracteres estava relacionada ao uso de uma cadeia de caracteres pelo OP
Isaac
1
@IharobAlAsimi Não escrevi o código. Você disse que era ilegível. Claramente, não é porque você e eu somos capazes de ler o código. É como discutir sobre gramática. 99% de todos os programadores são capazes de ler o código muito bem
Zuckerburg
55

Limpando a resposta de Isaac:

['mousemove', 'touchmove'].forEach(function(e) {
  window.addEventListener(e, mouseMoveHandler);
});

EDITAR

Função auxiliar ES6:

function addMultipleEventListener(element, events, handler) {
  events.forEach(e => element.addEventListener(e, handler))
}
pmrotule
fonte
1
FYI: map! = ForEach
jpoppe 31/03
10

Para mim; esse código funciona bem e é o código mais curto para lidar com vários eventos com as mesmas funções (em linha).

var eventList = ["change", "keyup", "paste", "input", "propertychange", "..."];
for(event of eventList) {
    element.addEventListener(event, function() {
        // your function body...
        console.log("you inserted things by paste or typing etc.");
    });
}
user3796876
fonte
Exatamente o que estou procurando. Obrigado!
Elharony 16/04/19
10

ES2015:

let el = document.getElementById("el");
let handler =()=> console.log("changed");
['change', 'keyup', 'cut'].forEach(event => el.addEventListener(event, handler));
ChrisTheButcher
fonte
Como alternativa, usando o for...ofloop
cara,
3

Eu tenho uma solução mais simples para você:

window.onload = window.onresize = (event) => {
    //Your Code Here
}

Eu testei isso e funciona muito bem, no lado positivo é compacto e descomplicado, como nos outros exemplos aqui.


fonte
1
Existe apenas um .onload possível. Talvez você substitua um antigo ouvinte. Dependendo do seu ambiente, isso pode ser um problema.
HolgerJeromin
1

AddEventListener usa uma sequência simples que representa event.type . Portanto, você precisa escrever uma função personalizada para iterar em vários eventos.

Isso está sendo tratado no jQuery usando .split ("") e, em seguida, iterando sobre a lista para definir os eventListeners para cada um types.

    // Add elem as a property of the handle function
    // This is to prevent a memory leak with non-native events in IE.
    eventHandle.elem = elem;

    // Handle multiple events separated by a space
    // jQuery(...).bind("mouseover mouseout", fn);
    types = types.split(" ");  

    var type, i = 0, namespaces;

    while ( (type = types[ i++ ]) ) {  <-- iterates thru 1 by 1
Selvakumar Arumugam
fonte
0

Uma maneira de fazer isso:

const troll = document.getElementById('troll');

['mousedown', 'mouseup'].forEach(type => {
	if (type === 'mousedown') {
		troll.addEventListener(type, () => console.log('Mouse is down'));
	}
        else if (type === 'mouseup') {
                troll.addEventListener(type, () => console.log('Mouse is up'));
        }
});
img {
  width: 100px;
  cursor: pointer;
}
<div id="troll">
  <img src="http://images.mmorpg.com/features/7909/images/Troll.png" alt="Troll">
</div>

Reza Saadati
fonte