2012-08-23 7 views
8

Ho un div in una pagina che mostra alcune informazioni su una particolare categoria (Immagine, Nome ecc.).Previene l'attivazione dell'evento sfocatura se uno dei suoi figli riceve lo stato attivo

Quando faccio clic sull'immagine di modifica, la categoria viene inserita in modalità di modifica che consente di aggiornare il nome. Come puoi vedere dall'immagine sottostante, mostra che "Soup" è attualmente in modalità di modifica, gli altri sono in modalità di visualizzazione normale. Tutto funziona come previsto con i pulsanti Annulla/Salva che fanno tutto bene. (Ho provato ad aggiungere un'immagine ma non me lo permetteva, ho bisogno di più amore)

Tuttavia una volta in modalità di modifica se faccio clic in qualsiasi altro punto della pagina (al di fuori del div) il risultato previsto sarebbe che la zuppa categoria tornerebbe alla modalità di visualizzazione. In caso di attivazione di un evento di qualche tipo, questo dovrebbe anche consentirmi di chiedere se volevano salvare le modifiche.

Quindi quello che ho deciso di fare è creare un evento di sfocatura sul div genitore "zuppe". Funziona come previsto se faccio clic in qualsiasi punto della pagina, tuttavia se faccio clic sull'elemento interno di div, viene generato anche l'evento di sfocatura dei genitori, quindi la categoria torna alla modalità di visualizzazione.

Quindi, c'è un modo per impedire al genitore di attivare l'evento sfocatura se uno dei suoi figli riceve lo stato attivo?

<div tabindex="-1" onblur="alert('outer')"> 
    <input type="text" value="Soup" /> 
</div> 

ho appena scritto il codice senza un compilatore quindi non so se funziona anche, ma con che si spera si ottiene l'idea.

Sto utilizzando Knockout.js per aggiornare la GUI al volo ma non dovrebbe influire su questa risposta non avrei pensato.

+0

[questione connessa] (http://stackoverflow.com/questions/121499/when-onblur-occurs-how-can-i-find -out-which-element-focus-went-to) – jbabey

risposta

21

Ho dovuto affrontare questo problema prima. Non sono sicuro se sia la soluzione migliore, ma è quello che ho finito per usare.

Poiché l'evento click si attiva dopo la sfocatura, non esiste un modo (cross-browser, affidabile) per indicare quale elemento sta diventando attivo.

Mousedown, tuttavia, gli incendi prima della sfocatura. Ciò significa che puoi impostare un po 'di bandiera nel mouse dei tuoi elementi figli e interrogare quella bandiera nella sfocatura del tuo genitore.

esempio di lavoro: http://jsfiddle.net/L5Cts/

Si noti che si dovrà anche gestire keydown (e controllare la scheda/shift-tab) se si vuole anche prendere sfuocature causata dalla tastiera.

+2

Signore, sei un gentiluomo e uno studioso.Ho provato diverse soluzioni a questo problema in diverse situazioni da oltre un anno. Non ho mai realizzato i tempi di tutti gli eventi, grazie mille. –

+0

Ho cercato di trovare una sorta di definizione ufficiale di ordine/precedenza degli eventi per vedere se è possibile fare affidamento su questo. Questa è una vecchia domanda, ma se la risposta è ancora vera questa soluzione potrebbe funzionare solo per coincidenza: https://stackoverflow.com/a/282271/2382483. Mi piacerebbe trovare una soluzione davvero solida a questo, ma tutto sembra essere un lavoro o un trucco. –

0

Non penso ci sia alcuna garanzia che mousedown accada prima degli eventi di messa a fuoco in tutti i browser, quindi un modo migliore per gestire questo potrebbe essere l'uso di evt.relatedTarget. Per l'evento focusin, la proprietà eventTarget è un riferimento all'elemento attualmente che perde lo stato attivo. Puoi controllare se quell'elemento è un discendente del genitore, e se non lo è, sai che il focus sta entrando nel genitore dall'esterno. Per l'evento focusout, relatedTarget è un riferimento all'elemento attualmente che riceve lo stato attivo. Utilizzare la stessa logica per determinare se messa a fuoco è completamente lasciando il genitore:

const parent = document.getElementById('parent'); 

parent.addEventListener('focusin', e => { 
    const enteringParent = !parent.contains(e.relatedTarget); 

    if (enteringParent) { 
     // do things in response to focus on any child of the parent or the parent itself 
    } 
}); 

parent.addEventListener('focusout', e => { 
    const leavingParent = !parent.contains(e.relatedTarget); 

    if (leavingParent) { 
     // do things in response to fully leaving the parent element and all of its children 
    } 
});