Único evento, comunicação e múltiplas interações

Geralmente definimos o evento no tag, por um dos atributos “on” ou no Javascript. Para cada elemento que precisa ser escutado um novo evento. O que eu mostro neste post é como adicionar um único evento no elemento raiz e ele valer para todas as tags. Mais do que isso, a possibilidade de novas interações, como delimitar escopos, agrupar valores, referências em comum.

O comum

Adicionar o evento na tag.

<button id="btn" onclick="alert('clique')">

Ou no Javascript.

<script>
// único
document.getElementById('btn').onclick = function() {
	alert('clique');
}

// pilha de eventos
document.getElementById('btn').addEventListerner('click', function() {
	alert('clique');
});
</script>

A outra forma

Atribuir o evento num elemento raíz, um elemento que englobe todos os outros elementos do seu teste. Não precisa ser no body. Então qualquer clique a partir desse elemento vai disparar esse evento único e vamos usar o event.target para navegador no DOM e encontrar os pontos chaves.

document.body.onclick = function(event) {
	// nó específico que recebeu o clique
	var node = event.target;
	
	// enquanto tiver um nó acima
	while (node.parentNode) {
		// buscar um atributo, valor ou o que você tiver determinado
		// pode ser até no conteúdo da tag (innerHTML)
		if (node.getAttribute('my-click')) {
			// alguma execução, eval, execução de função...
			eval(node.getAttribute('my-click'));
		}
		
		// continue subindo, mesmo que já tenha encontrado um nó
		// pode ser que no nível acima também tenha uma instrução
		// de execução
		node = node.parentNode;
	}
}

Até agora não deixa de ser um onclick personalizado. Mas podemos melhorar buscando outras referências, como um atributo que faça ligação com mais dados. No AngularJS seria uma controller.

document.body.onclick = function(event) {
	var node = event.target;
	var ref;
	
	while (node.parentNode) {
		if (node.getAttribute('my-click')) {
			// deste ponto em diante inicia-se
			// a busca pelas referências
			var ref = node;
			
			while (ref.parentNode) {
				if (ref.getAttribute('my-scope')) {
					// aqui você pode para a busca
					// ou continuar buscando nos níveis mais acima
					// neste exemplo vou parar e no mais abaixo
					// vou criar uma pilha para guardar todas essas
					// referências
					break;
				}
				
				// sobe equanto não encontrar uma referência
				// ou não existir nó acima
				ref = ref.parentNode;
			}
			
			// alguma ação...
			eval(node.getAttribute('my-click'));
		}
		
		// continua subindo até a raiz
		node = node.parentNode;
	}
}

Podemos melhorar

document.body.onclick = function(event) {
	var node = event.target;
	var ref;
	var stack;
	
	while (node.parentNode) {
		if (node.getAttribute('my-click')) {
			ref = node;
			stack = [];
			
			while (ref.parentNode) {
				if (ref.getAttribute('my-ref')) {
					// guarde o valor, elemento ou a referência que precisar
					stack.push(ref.getAttribute('my-ref'));
				}
				ref = ref.parentNode;
			}
			
			// interaja com a pilha (ou fila, como quiser trabalhar)
			for (var i = stack.length; i--;) {
				
			}
			
			// execute a ação
			eval(node.getAttribute('my-click'));
		}
		
		// continua percorrendo níveis acima
		node = node.parentNode;
	}
}

Exemplo completo

<div>
	<div my-ref="a">
		<button my-click="enter">Botão 1</button>
	</div>
	<div my-ref="b">
		<div my-ref="bb">
			<button my-click="leave">Botão 2</button>
		</div>
	</div>
</div>

<script>
var refs = {
	a: {
		i: 1
	},
	b: {
		i: 2,
		j: 3
	},
	bb: {
		j: 5
	}
};

function enter(args) {
	console.log('enter', args);
}

function leave(args) {
	console.log('leave', args);
}

document.body.onclick = function(event) {
	var node = event.target, ref, stack, set, item, i;
	
	while (node.parentNode) {
		if (node.getAttribute('my-click')) {
			ref = node;
			stack = [];
			
			while (ref.parentNode) {
				if (ref.getAttribute('my-ref')) {
					stack.push(ref.getAttribute('my-ref'));
				}
				ref = ref.parentNode;
			}
			
			set = {};
			
			while (item = stack.pop()) {
				for (var key in refs[item]) {
					set[key] = refs[item][key];
				}
			}
			
			window[node.getAttribute('my-click')](set);
		}
		
		node = node.parentNode;
	}
}
</script>

Clique no Botão 1 exibe no console enter Object {i: 1} e o clique no Botão 2 leave Object {i: 2, j: 5}.

You may also like...