2011-11-08 7 views
27

Stiamo lavorando su uno strumento JavaScript con codice precedente, , quindi non possiamo riscrivere l'intero strumento.Come gestisco un clic in qualsiasi punto della pagina, anche quando un determinato elemento interrompe la propagazione?

Ora, un menu è stato aggiunto posizione fissa in basso e il client sarebbe molto piaciuto avere un pulsante di commutazione per aprire e chiudere il menu, eccetto la chiusura deve avvenire automaticamente quando un utente inizia a fare le cose fuori lato del menu, ad esempio, quando un utente torna nella pagina e seleziona qualcosa o fa clic su un campo modulo.

Questo potrebbe tecnicamente lavorare con un evento click sul body, innescando su ogni clic, tuttavia ci sono numerosi elementi del vecchio codice, in cui un evento click è stato gestito su un link interno, e return false è stato aggiunto al click funzione, in modo che il sito non continui al tag href del collegamento.

Così chiaramente, una funzione generale come questa funziona, ma non quando si fa clic su un collegamento interno dove il ritorno false arresta la propagazione.

$('body').click(function(){ 
    console.log('clicked'); 
}); 

C'è un modo per forzare l'evento corpo click in ogni caso, o c'è un altro modo posso lasciare il dissappear menù, utilizzando alcune evento click globale o qualcosa di simile?

Senza dover riscrivere tutti gli altri clic nell'applicazione creati anni fa. Questo sarebbe un compito da mostro, soprattutto perché non ho idea di come li riscriverei, senza il falso ritorno, ma ancora non li lascerò andare al loro href.

risposta

44

Eventi a moderne implementazioni DOM hanno due fasi, catturando e spumeggiante.La fase di cattura è la prima fase, che scorre dal defaultView del documento al target dell'evento, seguita dalla fase di bubbling, che scorre dal target dell'evento indietro al defaultView. Per ulteriori informazioni, vedere http://www.w3.org/TR/DOM-Level-3-Events/#event-flow.

per gestire la fase di cattura di un evento, è necessario impostare il terzo argomento per addEventListener a true:

document.body.addEventListener('click', fn, true); 

Purtroppo, come detto Wesley, la fase di cattura di un evento non può essere gestito in modo affidabile, o a tutti, nei browser più vecchi.

Una possibile soluzione è quella di gestire l'evento mouseup invece, dal momento che fine evento per i clic è:

  1. mousedown
  2. mouseup
  3. click

Se si può essere sicuri di avere nessun handler che cancella l'evento mouseup, quindi questo è un modo (e, discutibilmente, un modo migliore) di andare. Un'altra cosa da notare è che molti, se non la maggior parte (se non tutti), i menu dell'interfaccia utente scompaiono al passaggio del mouse.

+2

Per chiunque si chieda se possono usare questo, ecco la pagina di caniuse: http://caniuse.com/#feat=addeventlistener la risposta breve è sì, a patto che non ti interessi su IE8 –

0

credo che questo sia quello che vi serve:

$("body").trigger("click"); 

Questo vi permetterà di attivare l'evento corpo click da qualsiasi luogo.

+0

si che il fuoco se qualcosa nidificato più profondo nel Regno impedisce la propagazione evento però? – Matt

+0

Penso che il problema è che gli eventi click vengono ingoiati restituendo false dai gestori eventi su determinati collegamenti, non che l'evento click non possa essere generato in primo luogo. –

0

Se assicurarsi che questo è il primo lavoro gestore evento, qualcosa di simile potrebbe fare il trucco:

$('*').click(function(event) { 
    if (this === event.target) { // only fire this handler on the original element 
     alert('clicked'); 
    } 
}); 

Nota che, se nella tua pagina ci sono molti elementi, questo sarà davvero molto lento e non funzionerà per qualcosa aggiunto dinamicamente.

+0

la cosa dinamica potrebbe essere facilmente risolta con $ ("*"). On ("click", function() {}); ma questa è una cattiva idea. – Bbit

6

In collaborazione con Andy E, questo è il lato oscuro della forza:

var _old = jQuery.Event.prototype.stopPropagation; 

jQuery.Event.prototype.stopPropagation = function() { 
    this.target.nodeName !== 'SPAN' && _old.apply(this, arguments); 
};  

Esempio: http://jsfiddle.net/M4teA/2/

Ricordate, se tutti gli eventi erano legati tramite jQuery, è possibile gestisci questi casi proprio qui. In questo esempio, chiamiamo semplicemente l'originale .stopPropagation() se non abbiamo a che fare con un <span>.


Non è possibile impedire l'impedimento, no.

Che cosa si potrebbe fare è, di riscrivere i gestori di eventi manualmente in-codice. Questo è un compito complicato, ma se sai come accedere ai metodi del gestore memorizzato, puoi risolvere il problema. Ho suonato in giro con un po ', e questo è il mio risultato:

$(document.body).click(function() { 
    alert('Hi I am bound to the body!'); 
}); 

$('#bar').click(function(e) { 
    alert('I am the span and I do prevent propagation'); 
    e.stopPropagation(); 
}); 

$('#yay').click(function() { 
    $('span').each(function(i, elem) { 
     var events  = jQuery._data(elem).events, 
      oldHandler = [ ], 
      $elem   = $(elem); 

     if('click' in events) {       
      [].forEach.call(events.click, function(click) { 
       oldHandler.push(click.handler); 
      }); 

      $elem.off('click'); 
     } 

     if(oldHandler.length) { 
      oldHandler.forEach(function(handler) { 
       $elem.bind('click', (function(h) { 
        return function() { 
         h.apply(this, [{stopPropagation: $.noop}]); 
        }; 
       }(handler))); 
      }); 
     } 
    }); 

    this.disabled = 1; 
    return false; 
}); 

Esempio: http://jsfiddle.net/M4teA/

Avviso, il codice precedente funziona solo con jQuery 1.7. Se quegli eventi di clic erano associati a una versione precedente di jQuery o "in linea", è comunque possibile utilizzare il codice ma è necessario accedere diversamente al "vecchio gestore".

so che sto assumendo un sacco di cose scenario "mondo perfetto" qui, per esempio, che quelle maniglie chiamano esplicitamente .stopPropagation() invece di ritornare false. Quindi è ancora potrebbe essere un esempio accademico inutile, ma mi sentivo di uscire con esso :-)

modificare: hey, return false; funzionano bene, gli oggetti evento si accede allo stesso modo.

+0

Questo è intelligente. :) –

Problemi correlati