Nota: apenas traduzi o texto abaixo e postei aqui.
Hoje, veremos abordagens para usar event delegation com múltiplos seletores.
Como isso funciona
Se você não está familiarizado com a abordagem, veja como funciona. Em vez de attaching events a elementos específicos, você "listen" esse event em um parent element (geralmente o document
ou window
).
Qualquer event desse tipo que aconteça dentro do parent element aparece e você pode filtrar aqueles que não match ao element que você está procurando.
document.addEventListener('click', function (event) {
// Verifica a classe .click-me
// Se o elemento clicado não possui ela, não faça nada
if (!event.target.matches('.click-me')) return;
// O código que você quer executar vai aqui
});
Se você estiver "listen" events em mais de um element com o mesmo seletor, essa abordagem é realmente melhor para desempenho porque usa menos memória no navegador.
Múltiplos seletores
Quando compartilho essa abordagem, muitas vezes os alunos me perguntam como implementá-la quando você precisa "listen" o mesmo tipo de event para vários seletores diferentes e fazer coisas diferentes com base no seletor que o elemento possui.
Por exemplo, digamos que você tenha botões mostrar/ocultar conteúdo que possuem uma classe .show-me
e outro conjunto de botões com a classe .save
que salva o conteúdo de um form para reutilização posterior.
Como você analisa quais ações serão executadas com base no seletor?
Opção 1: separe event listeners
A abordagem mais óbvia é usar dois event listeners separados, um para cada seletor.
document.addEventListener('click', function (event) {
if (!event.target.matches('.show-me')) return;
// Revele o conteúdo escondido...
});
document.addEventListener('click', function (event) {
if (!event.target.matches('.save')) return;
// Salve o conteúdo do form...
});
Essa abordagem funciona bem se seus scripts forem mantidos em arquivos modulares separados.
Embora você esteja usando dois event listeners em vez de um, isso ainda é muito melhor para o desempenho do que "attaching" um listener a cada botão correspondente.
Opção 2: if...else
Se os dois trechos de código estiverem no mesmo arquivo, você poderá combiná-los em um único event listener
e usar uma instrução if...else if
.
document.addEventListener('click', function (event) {
if (event.target.matches('.show-me')) {
// Revele o conteúdo escondido...
} else if (event.target.matches('.save')) {
// Salve o conteúdo do form...
}
});
Isso proporciona um pequeno aumento de desempenho.
Opção 3: if e return
Muitas pessoas acham as instruções if...else if
difíceis de manejar, especialmente se você tiver mais do que apenas algumas verificações. Eles podem crescer rapidamente e sair fora de controle.
Por esse motivo, prefiro usar instruções if sequenciais, com "returns" entre chaves para encerrar a function quando ocorrer um match.
document.addEventListener('click', function (event) {
if (event.target.matches('.show-me')) {
// Revele o conteúdo escondido...
return;
}
if (event.target.matches('.save')) {
// Salve o conteúdo do form...
return;
}
});
Essa abordagem é, para mim, mais fácil de ler. Isso também significa que posso movimentar minhas verificações sem me preocupar em quebrar nada.
Opção 4: handler functions
Se você gosta de programação funcional, essa abordagem fornece uma estrutura interessante.
Dentro do event listener callback
, você chama handler functions
separadas para cada seletor e passa o event object. Em cada handler function
, você executa a verificação do seletor e executa o código de acordo.
var showMe = function (event) {
if (!event.target.matches('.show-me')) return;
// Revele o conteúdo escondido...
};
var saveMe = function (event) {
if (!event.target.matches('.save')) return;
// Salve o conteúdo do form...
};
document.addEventListener('click', function (event) {
showMe(event);
saveMe(event);
});
Essa abordagem fornece um bom equilíbrio entre desempenho e capacidade de manutenção.
O desempenho é um pouco menor do que as opções 2 e 3, porque a function saveMe()
será executada mesmo se showMe()
encontrar um match (as outras duas abordagens param assim que um match é encontrado). Mas ainda é melhor do que ter event listeners separados e fornece uma estrutura de código limpa e legível.
Qual abordagem você deve usar?
Em última análise, depende do seu projeto.
Eu uso muito a opção 1, porque costumo manter meus scripts em arquivos modulares. Mas quando o código está todo em um arquivo, a opção 4 é minha favorita.
Sugestão (atualizado):
Através da execução de Array.prototype.some
da lista das handler functions, você pode executar somente até a primeira que retorne true
, desde de que todas elas retornem isso (ou undefined
no caso negativo) durante as verificações.
var showMe = function (event) {
if (!event.target.matches('.show-me')) return;
// Revele o conteúdo escondido...
return true;
};
var saveMe = function (event) {
if (!event.target.matches('.save')) return;
// Salve o conteúdo do form...
return true;
};
var otherLogic1 = function (event) {
// a verificação negativa
// a lógica
return true;
}
var otherLogic2 = function (event) {
// a verificação negativa
// a lógica
return true;
}
document.addEventListener('click', function (event) {
[showMe, saveMe, otherLogic1, otherLogic2].some(
handler => Boolean(handler(event))
);
});
Array.prototype.some
interrompe sua iteração interna quando a primeira execução da sua callback function
retornar true
.
Fonte
Newsletter de Go Make Things
Top comments (0)