2012-02-02 19 views
20

Estoy tratando de encontrar la manera de vincular un evento con elementos creados dinámicamente. Necesito que el evento persista en el elemento incluso después de que se haya destruido y regenerado.Implementando la carpeta "en vivo" de jQuery con Javascript nativo

Obviamente, con la función de jQuery en vivo es fácil, pero ¿qué iban a parecerse a cabo con Javascript nativa?

+1

Siempre puede leer la fuente jQuery: p. Sin embargo, no estoy seguro de cuán lejos estaría del JS nativo, ya que estoy seguro de que dependerá en gran medida de sí mismo en ese punto (en términos de usar selectores y demás). – Corbin

+0

Solo una nota: '.live()' está en desuso por mucho, mucho tiempo. Fue reemplazado por '.delegate()', que fue reemplazado por '.on()', así que use el último. Además, el último muestra la diferencia entre vincular y delegar, por lo que es posible que desee echar un vistazo. Lo más importante es verificar el objetivo del evento. – Tadeck

+0

Esta respuesta de mina puede ayudar a http://stackoverflow.com/a/27373951/1385441 –

Respuesta

21

Aquí está un ejemplo sencillo:

function live(eventType, elementId, cb) { 
    document.addEventListener(eventType, function (event) { 
     if (event.target.id === elementId) { 
      cb.call(event.target, event); 
     } 
    }); 
} 

live("click", "test", function (event) { 
    alert(this.id); 
}); 

La idea básica es que desea adjuntar un controlador de eventos para el documento y dejar que el cuadro del evento hasta el DOM. Luego, verifique la propiedad event.target para ver si coincide con los criterios deseados (en este caso, solo que el id del elemento).

Editar:

@shabunc descubrieron un problema bastante grande con mis eventos solution-- sobre elementos secundarios no se detectará correctamente. Una forma de solucionar este problema es mirar a elementos antecesores para ver si alguno ha especificado id:

function live (eventType, elementId, cb) { 
    document.addEventListener(eventType, function (event) { 
     var el = event.target 
      , found; 

     while (el && !(found = el.id === elementId)) { 
      el = el.parentElement; 
     } 

     if (found) { 
      cb.call(el, event); 
     } 
    }); 
} 
+0

al documento o - de manera más eficiente - con el recipiente fuera de la cual no esperas elementos de su interés. – Tadeck

+0

De modo que escucha cualquier evento de clic y cuando se produce un evento de clic, comprueba si la ID del objetivo coincide con la identificación proporcionada o no y realiza la función de devolución de llamada. Bastante Interesante :) – InspiredJW

+0

Derecha. Y como señala @Tadeck, puede limitar el burbujeo a otro elemento que lo contenga para un oyente más eficiente. –

14

, además del puesto de Andrew y el comentario de Binyamin, tal vez esta es una opción:

Con esto se puede use 'nav .item a' como selector. Basado en el código de Andrew.

function live (eventType, elementQuerySelector, cb) { 
    document.addEventListener(eventType, function (event) { 

     var qs = document.querySelectorAll(elementQuerySelector); 

     if (qs) { 
      var el = event.target, index = -1; 
      while (el && ((index = Array.prototype.indexOf.call(qs, el)) === -1)) { 
       el = el.parentElement; 
      } 

      if (index > -1) { 
       cb.call(el, event); 
      } 
     } 
    }); 
} 



live('click', 'nav .aap a', function(event) { console.log(event); alert('clicked'); }); 
+0

Muchas gracias. Una cosa que sugeriría es suporting 'e.preventDefault()' inside 'addEventListener'. Si se usa, tendrá que cambiarlo a 'document.querySelector (elementQuerySelector) .addEventListener (eventType, function (event) {' de lo contrario, evitará que haga clic en cualquier otro elemento de la página – Lodder

0

Una alternativa para vincular un evento dinámicamente a un elemento específico podría ser un detector de eventos global. Por lo tanto, cada vez que actualice el DOM con otro evento de elemento nuevo en ese elemento también lo "atrapará". Un ejemplo:

var mybuttonlist = document.getElementById('mybuttonlist'); 
 

 
mybuttonlist.addEventListener('click', e=>{ 
 
    if(e.target.nodeName == 'BUTTON'){ 
 
    switch(e.target.name){ 
 
     case 'createnewbutton': 
 
     mybuttonlist.innerHTML += '<li><button name="createnewbutton">Create new button</button></li>'; 
 
     break; 
 
    } 
 
    } 
 
}, false);
ul { 
 
    list-style: none; 
 
    padding: 0; 
 
    margin: 0; 
 
}
<ul id="mybuttonlist"> 
 
    <li><button name="createnewbutton">Create new button</button></li> 
 
</ul>

En este ejemplo tengo un detector de eventos en el <ul> de eventos de clic. Entonces, ocurre un evento para todos los elementos secundarios. Desde el simple controlador de eventos que creé, puede ver que es fácil agregar más lógica, más botones (con nombres diferentes o repetidos), anclajes, etc.

Yendo all-in, puede agregar el eventlistener al documento en lugar de el elemento de lista, capturando todos los eventos de clic en la página y luego manejando los eventos de clic en el controlador de eventos.

Cuestiones relacionadas