2012-02-02 11 views
20

Sto cercando di capire come associare un evento a elementi creati dinamicamente. Ho bisogno che l'evento persista sull'elemento anche dopo che è stato distrutto e rigenerato.Implementazione del binder "live" di jQuery con Javascript originale

Ovviamente con la funzione live di jQuery è facile, ma come sarebbero implementati con JavaScript nativo?

+1

Si può sempre leggere la fonte jQuery: p. Non sono sicuro di quanto sarebbe lontano dal JS nativo, dal momento che sono sicuro che dipenderà molto da sé da quel punto (in termini di utilizzo di selettori e quant'altro). – Corbin

+0

Solo una nota: '.live()' è deprecato per molto, molto tempo. È stato sostituito da '.delegate()', che è stato sostituito da '.on()', quindi per favore usa l'ultimo. Inoltre, l'ultimo mostra la differenza tra l'associazione e la delega, quindi potresti voler dare un'occhiata. Il più importante è il controllo dell'evento target. – Tadeck

+0

Questa mia risposta può aiutare http://stackoverflow.com/a/27373951/1385441 –

risposta

21

Ecco un semplice esempio:

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); 
}); 

L'idea di base è che si desidera collegare un gestore di eventi per il documento e lasciare che la bolla dell'evento il DOM. Quindi, controlla la proprietà event.target per vedere se soddisfa i criteri desiderati (in questo caso, solo che l'elemento id).

Edit:

@shabunc scoperto un abbastanza grande problema con i miei eventi solution-- su elementi bambino non sarà rilevato correttamente. Un modo per risolvere questo problema è quello di esaminare gli elementi antenati per vedere se hanno specificato 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 - in modo più efficiente - al contenitore al di fuori del quale non ti aspetti elementi di tuo interesse. – Tadeck

+0

Quindi questo sta ascoltando solo un evento click e quando si verifica un evento click, controlla se l'id del target corrisponde o meno all'ID dato e fa la funzione callback. Piuttosto interessante :) – InspiredJW

+0

Giusto. E come sottolinea @Tadeck, puoi limitare il bubbling a un altro elemento contenente un listener più efficiente. –

14

Oltre al post di Andrea e il commento di Binyamin, forse questa è un'opzione:

Con questo si può usa 'nav .item a' come selettore. Basato sul codice di 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

Grazie mille. Una cosa che suggerirei è la presenza di "e.preventDefault()" all'interno di "addEventListener". Se utilizzato, sarà necessario cambiarlo in 'document.querySelector (elementQuerySelector) .addEventListener (eventType, function (event) {' altrimenti impedirà di fare clic su qualsiasi altro elemento nella pagina – Lodder

0

Un'alternativa al collegamento di un evento a un elemento specifico in modo dinamico potrebbe essere un listener di eventi globale. Quindi, ogni volta che aggiorni il DOM con un altro nuovo evento di elemento su quell'elemento, verranno visualizzati anche i "catture". Un esempio:

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>

In questo esempio ho un listener di eventi sul <ul> per gli eventi click. Quindi, un evento accade per tutti gli elementi figli. Dal semplice gestore di eventi che ho creato, puoi vedere che è facile aggiungere più logica, più pulsanti (con nomi diversi o ripetuti), ancore ecc.

All'ingresso, è possibile aggiungere l'eventlistener al documento anziché l'elemento list, che cattura tutti gli eventi click sulla pagina e quindi gestisce gli eventi click nel gestore eventi.