2009-07-21 4 views
12

Simile a this question, ma facendo un ulteriore passo avanti. Vorrei rilevare clic al di fuori di un insieme di elementi, che sto maneggiando nel modo seguente:Rileva clic su elemento esterno?

$('#menu div').live('click', function() { 
    // Close other open menu items, if any. 
    // Toggle the clicked menu item. 

    $('body').one('click', function(event) { 
     // Hide the menu item. 
     event.stopPropagation(); 
    }); 
}); 

Questo funziona come un fascino, purtroppo, quando un altro elemento del menu è aperto e un secondo viene cliccato, richiede due clic per aprire il secondo elemento. Il primo clic su nasconde la prima voce di menu che era aperta, la seconda mostra il secondo elemento di menu .

Il comportamento "corretto" funziona nel seguente modo:

  • Cliccando una voce di menu apre.
  • Se si fa clic sulla stessa voce di menu (o sui suoi figli) lo si chiude.
  • Facendo clic su un'altra voce di menu si chiude la prima, si apre la seconda.
  • Cliccando al di fuori delle voci di menu (aperte) le si chiude.

Ho provato quanto segue in luogo di quanto sopra $('body').one() fine di ignorare clic su voci di menu con scarso successo:

// Captures click on menu items in spite of the not. 
$('*').not('#menu *').one('click', function() { // Hide menu } 
$('*:not(#menu)').one('click', function() { // Hide menu } 

Come sempre, grazie per qualsiasi aiuto!

risposta

29

Basta muovere il gestore corpo click fuori e fare qualcosa del genere:

$('body').bind('click', function(e) { 
    if($(e.target).closest('#menu').length == 0) { 
     // click happened outside of menu, hide any visible menu items 
    } 
}); 

E 'stato erroneamente segnalato nei commenti che e.target non funziona in IE; questo non è vero in quanto jQuery's Event object corregge queste incoerenze laddove necessario (IE, Safari).

+0

Qual è lo scopo di spostare il 'body' clic handler di fuori del click gestore di menu? Sembra che esegua lo stesso compito (senza il sovraccarico di prendere ogni click del corpo se il menu non viene mai aperto) applicandolo dopo l'apertura di una voce di menu. O mi sta sfuggendo qualcosa? – chuckg

+0

È un punto giusto; Considero l'overhead di legare e slegare un evento ogni volta che un utente fa clic su una voce di menu non necessaria. Di solito non ci sarà molto clic su una pagina oltre ad andare in un'altra pagina, nel qual caso il gestore di clic in più è completamente irrilevante. Alla fine della giornata, entrambi sono a posto a seconda delle esigenze, quindi è possibile attenersi al gestore se si adatta alle proprie esigenze. –

+0

e.target non funziona su IE ... –

15

Ho scritto questo molto tempo fa, prima che i giorni di gloria di jQuery ...

function clickedOutsideElement(elemId) { 
    var theElem = getEventTarget(window.event); 
    while(theElem != null) { 
    if(theElem.id == elemId) 
     return false; 
    theElem = theElem.offsetParent; 
    } 
    return true; 
} 

function getEventTarget(evt) { 
    var targ = (evt.target) ? evt.target : evt.srcElement; 
    if(targ != null) { 
    if(targ.nodeType == 3) 
     targ = targ.parentNode; 
    } 
    return targ; 
} 

document.onclick = function() { 
    if(clickedOutsideElement('divTest')) 
    alert('Outside the element!'); 
    else 
    alert('Inside the element!'); 
} 
+0

jQuery corregge e.target come cross browser, rendendo così inutile tutto questo trambusto. :) –

+0

Tutto ciò è discutibile se si supporta solo IE9 +, è ora corretto http://msdn.microsoft.com/en-us/library/ie/ff974946%28v=vs.85%29.aspx – Gabe