queryselectorall javascript events loops click listeners

queryselectorall - addeventlistener javascript



Agregar oyentes de eventos ''click'' en loop (5)

Esta pregunta ya tiene una respuesta aquí:

Refactoring standard onClick dentro de la etiqueta html a los oyentes, se enfrentó a un problema con mi código:

var td; for (var t=1;t<8;t++){ td = document.getElementById(''td''+t); if (typeof window.addEventListener===''function''){ td.addEventListener(''click'',function(){ console.log(td); })} }

Cuando se hace clic en el elemento td , se supone que hizo clic en td con el último índice del bucle, por ejemplo, 7
Parece que eventListeners ha eventListeners para el último elemento en este ciclo.
La inicialización del bucle parece correcta.
¿Por qué sucedió eso?

Aquí está el código en vivo


Debes ajustar la tarea del oyente del evento en un cierre, algo así como:

var td; for (var t = 1; t < 8; t++){ td = document.getElementById(''td''+t); if (typeof window.addEventListener === ''function''){ (function (_td) { td.addEventListener(''click'', function(){ console.log(_td); }); })(td); } }


Entonces, lo que está sucediendo aquí es que está manteniendo la variable ''td'' en el alcance para la función de escucha de eventos. Solo hay 1 instancia de ''td'', y eso se actualiza cada vez que se repite el ciclo for. Por lo tanto, cuando el bucle for finaliza, el valor de td ahora se establece en el elemento ''# td7'' y su controlador de eventos simplemente registra el valor actual de td.

En el ejemplo anterior, simplemente puede registrar ''this'':

var td; for (var t=1;t<8;t++){ td = document.getElementById(''td''+t); if (typeof window.addEventListener===''function''){ td.addEventListener(''click'',function(){ console.log(this); }); } }

dado que ''this'' se establece en el elemento al que se vinculó un evento para la ejecución de un controlador de eventos.

Supongo que está buscando más respuestas sobre mantener el iterador al crear cierres desde dentro de un bucle for. Para hacer esto, desea definir una función fuera del ciclo for.

for (var t=1;t<8;t++){ bind_event(t); } function bind_event(t) { var td = document.getElementById(''td''+t); if (typeof window.addEventListener===''function''){ td.addEventListener(''click'',function(){ console.log(td); }); } }

De esta forma, se crea una instancia de una variable llamada ''td'' cada vez que se ejecuta bind_event, y esa instancia se mantendrá cerrada para la función del detector de eventos. Vale la pena señalar que ''t'' en bind_event también es una nueva variable.


Según tengo entendido, sucede a causa del cierre ... asigna el manejador de eventos dentro del alcance de la instrucción FOR. Cuando se produce un clic, toma la última versión si la variable TD está dentro del alcance de FOR y la escribe para iniciar sesión.


lo siguiente debería funcionar como se espera:

for (var t=1;t<8;t++){ var td; td = document.getElementById(''td''+t); if (typeof window.addEventListener===''function''){ td.addEventListener(''click'',function(){ console.log(this); })} }


Qué esta pasando

La variable td se define fuera de los manejadores de eventos, por lo que cuando hace clic en una celda, está registrando el último valor en el que se configuró.

Más técnicamente: cada función del controlador de eventos es una función de cierre, que hace referencia a variables de un ámbito externo.

La solución general

La solución general a este tipo de problema es devolver el controlador de eventos desde una función de contenedor, pasando las variables que desea "arreglar" como argumentos:

td.addEventListener(''click'', function(wrapTD) { return function() { console.log(wrapTD); } }(td));

Los argumentos están ahora vinculados al alcance de la función de contenedor invocado.

Solución más simple: use this

Sin embargo, hay una opción aún más simple. En un controlador de eventos, this se establece en el elemento en el que se define el controlador , por lo que puede usar this lugar de td :

td.addEventListener(''click'', function() { console.log(this); });

Incluso más simple: ¡sin bucle!

Finalmente, puede deshacerse for completo del bucle for y establecer un único manejador de eventos en toda la tabla:

var table = document.getElementById(''my-table''); table.addEventListener(''click'', function(e) { if (e.target.nodeName.toUpperCase() !== "TD") return; var td = e.target; console.log(td); });

Esta es una solución mucho mejor para tablas más grandes, ya que está reemplazando múltiples manejadores de eventos con solo uno. Tenga en cuenta que si ajusta su texto en otro elemento, deberá adaptarlo para verificar si el elemento objetivo es un descendiente de un td .