2016-04-05 59 views
7

Voglio creare un evento singolo attivato facendo clic ovunque. Questo evento viene creato facendo clic su un pulsante. Non voglio che l'evento si attivi a seguito del clic sul pulsante, solo i clic successivi ovunque (incluso il pulsante).setTimeout e propagazione evento

Quindi dire che ho avuto qualche HTML simile al seguente:

<body> 
    <div id="someparent"> 
    <div id="btn"></div> 
    </div> 
</body> 

E il seguente javascript (jQuery):

$('#btn').click(function() { 
    $(document).one('click', function() { 
    console.log('triggered'); 
    }); 
}); 

$('#someparent').click(function() { 
    // this must always be triggered 
}); 

voglio evitare di fermarsi propagazione degli eventi, ma in quanto sopra Ad esempio, l'evento è destinato a documentare, quindi l'evento esplode e l'evento viene attivato.

Un modo per risolvere questo problema sembra essere quello di avvolgere la creazione di eventi in un timeout:

$('#btn').click(function() { 
    setTimeout(function() { 
    $(document).one('click', function() { 
     console.log('triggered'); 
    }); 
    }, 1); 
}); 

$('#someparent').click(function() { 
    // this must always be triggered 
}); 

Ora, questo funziona bene, ma mi chiedo se questo è sicuro. Qualche idea di ordine di esecuzione garantisce che funzioni sempre, o funziona solo per caso? So che ci sono altre soluzioni (ad esempio un altro evento nidificato .one()), ma sono specificamente alla ricerca di una risposta a come setTimeout e la propagazione degli eventi interagiscono.

Il seguente violino mostra due div. Il primo ha il comportamento sbagliato (l'evento del documento viene attivato immediatamente). Facendo clic sul secondo div, e quindi in un punto qualsiasi del documento (area bianca) illustra il comportamento desiderato:

https://jsfiddle.net/Lwocuuf8/7/

+0

Non riesci a cablare l'evento click e semplicemente rimuovere la maniglia una volta che l'evento ha stato attivato (a meno che la sorgente sia il pulsante)? –

+0

Non sono sicuro di capire cosa intendi? – jkgeyti

+0

è sufficiente restituire false per evitare bolle sparse – TecHunter

risposta

7

evento di bubbling significa che, dopo un evento attiva sull'elemento più profondo possibile, si innesca quel momento in poi i genitori in nidificazione ordine.

Da: https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#Adding_messages

l'aggiunta di messaggi

nei browser web, i messaggi vengono aggiunti ogni volta che si verifica un evento e ci è un listener di eventi collegato ad esso. Se non c'è nessun listener, l'evento viene perso. Quindi un clic su un elemento con un gestore di eventi click aggiungerà un messaggio - allo stesso modo con qualsiasi altro evento.

La chiamata a setTimeout aggiungerà un messaggio alla coda dopo che l'ora è passata come secondo argomento. Se non c'è nessun altro messaggio in coda, il messaggio viene elaborato subito; tuttavia, se ci sono messaggi, il messaggio setTimeout dovrà attendere che gli altri messaggi siano elaborati . Per questo motivo il secondo argomento indica un tempo minimo e non un orario garantito.

Così, il comportamento si ha, non a caso, si ha la garanzia che i messaggi nella coda saranno trattati prima l'elaborazione del messaggio si aggiunge dopo un timeout.

+1

esattamente quello che stavo cercando. Questo garantisce il comportamento previsto. Grazie. – jkgeyti

2

La mia comprensione di ciò che si desidera: dopo aver fatto clic su un pulsante "attivazione", il successivo clic in qualsiasi punto della pagina (compreso il pulsante "attivazione") dovrebbe attivare un evento speciale.Questo è facilmente gestito con una bandiera:

var activationFlag = false; 

$('#btn').click(function(event){ 
    event.preventDefault(); 

    if(!activationFlag) { 
    event.stopPropagation(); 
    console.log('Global event activated'); 
    } 

    activationFlag = true; 
}); 

$('#someparent').click(function(event){ 
    if(activationFlag) { 
    console.log('Time for a special event'); 
    } else { 
    event.preventDefault(); 
    event.stopPropagation(); 
    } 
}); 
+1

Grazie. È un esempio inventato costruito da un problema del mondo reale, quindi sembra un po 'strano. Esistono numerose soluzioni migliori rispetto all'approccio 'setTimeout' che ho usato, ma cercavo specificatamente una risposta per verificare se il comportamento previsto fosse garantito. Tuttavia, sono d'accordo sul fatto che un flag sia la soluzione appropriata in questo caso, sebbene eviterei di fermare la propagazione degli eventi come fai nel tuo esempio. – jkgeyti

2

Here is a workaround utilizzando un flag al posto di un secondo evento:

var documentWaitingClick = false; 
$(function() { 
    $(document).on('click', function(e) { 
    if (documentWaitingClick) { 
     //simulate the "one" 
     documentWaitingClick = false; 
     console.log('document click'); 
    } else if (e.target.tagName === 'BUTTON') { 
     documentWaitingClick = true; 
     console.log('button click') 
    } 
    }); 
});