VanillaJS e addEventListener para aplicações grandes e/ou single page #119
Replies: 5 comments
-
c/c @fdaciuk |
Beta Was this translation helpful? Give feedback.
-
Tá procurando algo como um event handler global, @felquis ? // ES6
const evtbar = {
_events: new Set(),
_handlers: {},
addHandler: (eventName, selector, handler) => {
const self = evtbar;
if ( !self._events.has(eventName) ) {
self._events.add(eventName);
self._listenTo(eventName);
}
self._handlers[selector] = (self._handlers[selector] || []).concat([handler])
},
_listenTo: (eventName) => {
const self = evtbar;
document.body.addEventListener(eventName, (event) => {
const element = event.target;
Object.keys(self._handlers)
// get selectors that matches element
.filter(selector => element.matches(selector))
// get handler list for each selector
.map(selector => self._handlers[selector])
// flat handlers
.reduce((sum, handlers) => sum.concat(handlers), [])
.forEach(handler => {
try {
handler.bind(element)(event)
} catch (err) {
console.error(err);
}
});
});
}
}; Precisa ainda dar split no Sobre alternativas ao ** tive que fazer o |
Beta Was this translation helpful? Give feedback.
-
No caso do matches, acho que estou fazendo algo errado mesmo. var element = document.querySelector('.list')
element.addEventListener('click', onListItemClick)
function onListItemClick (event) {
console.dir(event)
} ul.list
li.list-item.active
a.list-item-anchor Item 1 Usuário clica no Ai eu fiz essa leve gambiarra.. var matches = (function () {
// https://developer.mozilla.org/en/docs/Web/API/Element/matches
var vendors = ['matches', 'matchesSelector',
'msMatchesSelector', 'webkitMatchesSelector',
'oMatchesSelector']
var useVendor = 'matches'
// Verifica os vendors
if (!document.body.matches) {
vendors.forEach(function verificaVendor(vendor) {
if (!!document.body[vendor]) { useVendor = vendor }
})
}
return function matches(target, selector) {
if(!target) { return false }
return (target[useVendor](selector))? target : matches(target.parentElement, selector)
}
}()) Se não der matche no element, executa a função matches para o target.parentElement... Fica recursivo até encontrar target, ou até chegar em Ai a mesma demonstração ficaria assim: http://codepen.io/felquis/pen/yOKQmq abre o console e da uma olhada no caminho percorrido pela função matches, procurando o target correto usando element.parentElement, isso me pareceu feio pq ele sobe até o máximo que pode... O ideal seria subir até o container do evento delegato, neste caso o até o click .list-item inside .list not outside Levando este meu código como exemplo, o que eu queria é parecido com um eventHandler on('event', 'target selector', 'container selector', handler) Caso tenha o mesmo // modulo 1
on('click', 'a', document, handler) // usa document.addEventListener internamente
// modulo 2
on('click', 'a', document, handler) // Usa o mesmo document.addEventListener usado acima, sem adicionar outro. Se eu tiver viajando na maionese me avisem por favor.. |
Beta Was this translation helpful? Give feedback.
-
Saquei... da pra fazer no baseado no script que escrevi até; Sobre o uso do matches.. vc poderia fazer o inverso... a partir do momento que vc tem o const parents = Array.prototyle.slice(document.querySelectorAll(parentSelector), 0);
const isOrContainsSelectors = parents.some(parent => parent.contains(element.target)); Sobre os handlers, poderia ser algo assim: const evtbar = {
_events: {},
_handlers: {},
addHandler: (eventName, selector, container, handler) => {
container = container || document.body;
const self = evtbar;
self._events[container] = (self._events[container] || new Set());
if ( !self._events[container].has(eventName) ) {
self._events[container].add(eventName);
self._listenTo(eventName, container);
}
self._handlers[container][selector] = (self._handlers[container][selector] || []).concat([handler])
},
_listenTo: (eventName, container) => {
const self = evtbar;
container.addEventListener(eventName, (event) => {
const element = event.target;
Object.keys(self._handlers)
// get selectors that matches element
.filter(selector => element.matches(selector))
// get handler list for each selector
.map(selector => self._handlers[selector])
// flat handlers
.reduce((sum, handlers) => sum.concat(handlers), [])
.forEach(handler => {
try {
handler.bind(element)(event)
} catch (err) {
console.error(err);
}
});
});
}
}; |
Beta Was this translation helpful? Give feedback.
-
curti esse código |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Olá - https://twitter.com/felquis/status/720283246286647296
Mantenho um projeto grande, feito com VanillaJS, e hoje em dia não possui nenhum teste, apenas um JSHint básico para não cometer gafes.
No momento da vida do projeto, não vejo a necessidade de implementar testes, porém vejo a necessidade de melhorar o método de uso do addEventListener, pois vários eventos ao mesmo elemento, vários eventos ao
window
oudocument
começam a mostrar efeitos colaterais indesejáveis.Situações
Caso 1: Um botão de seguir. É usado um evento de touchstart, touchend & click no
document
ambos os eventos resultam na execução de uma função baseada nos atributos data-* dos elementosCaso 2: Um botão de opções/options, é deletado no
document
ao ser acionado e o target identificado, e o modulo é acionado conforme as informações presentes nos atributos data-*Identificação do target do click no
document
para delegação de eventos, o que era muito comum no jQuery com o.live
, e hj em dia no.on
, porém identificar o target é uma tarefa não tão simples. Em que uso um element.matches recursivo, que sobe a hierarquia de elementos até possivelmente encontrar o target. Isso é simples para elementos simples, comoa > span
, porém complicado quando tem composição de elementos...Observações: Não é usado
stopPropagation
em hipótese alguma, apenas se for case de hacks, o que não há e há alto uso depreventDefault
.Necessidade
Gostaria de saber se há conhecimento de alguma lib, que minimiza o uso de addEventListeners desnecessários quando usado em um mesmo elemento, no caso de event delegation em um
container
,document
ouwindow
.E também algo que me ajude a usar o matches com mais clareza.. pode ser tanto junto ao parágrafo acima ou um módulo a parte.
E também que compartilhassem a experiência de vocês com addEventListener em VanillaJS e apps em que o conteúdo é 100% dinâmico, adicionado e removido via JS.
Obrigado, até mais.
Beta Was this translation helpful? Give feedback.
All reactions