2009-07-21 6 views
12

Semblable à this question, mais en prenant un peu plus loin. Je voudrais détecter clique à l'extérieur d'un ensemble d'éléments, que je traitais de la manière suivante:Détecter un clic sur un élément externe?

$('#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(); 
    }); 
}); 

Cela fonctionne comme un charme, malheureusement, quand un autre élément de menu est ouvert et une seconde est cliqué, il faut deux clics pour ouvrir le deuxième élément. Le premier clic masque le premier élément de menu qui était ouvert, le second le deuxième élément du menu .

Le comportement "correct" fonctionne de la manière suivante:

  • En cliquant sur un élément de menu ouvre.
  • En cliquant sur le même élément de menu (ou ses enfants) le ferme.
  • Cliquer sur un autre élément de menu ferme le premier, ouvre le second.
  • En cliquant à l'écart des éléments de menu (ouverts), vous les fermez.

J'ai essayé ce qui suit à la place du $('body').one() ci-dessus afin de ne pas tenir compte des clics sur des éléments de menu avec peu de succès:

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

Comme toujours, merci pour toute aide!

Répondre

29

il suffit de déplacer le gestionnaire de clic du corps extérieur et faire quelque chose comme ceci:

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

Il a été mal fait remarquer dans les commentaires que e.target ne fonctionne pas dans IE; ce n'est pas vrai car jQuery's Event object corrige ces incohérences si nécessaire (IE, Safari).

+0

Quel est le but de déplacer le 'body' cliquez gestionnaire en dehors du menu gestionnaire de clic? Il semble accomplir la même tâche (sans le surcoût d'attraper chaque clic de corps si le menu n'est jamais ouvert) en l'appliquant après l'ouverture d'un élément de menu. Ou est-ce que je manque quelque chose? – chuckg

+0

C'est un bon point; Je considère le surcoût de liaison et de désengagement d'un événement chaque fois qu'un utilisateur clique sur un élément de menu inutile. Habituellement, il n'y aura pas beaucoup de clics sur une page en dehors d'aller à une autre page, dans ce cas, le gestionnaire de clic supplémentaire est complètement hors de propos. À la fin de la journée, les deux sont bien en fonction de vos besoins, vous pouvez donc vous en tenir au gestionnaire si cela correspond à vos besoins. –

+0

e.target ne fonctionne pas sur IE ... –

15

J'ai écrit ce depuis longtemps, avant que les jours de gloire de 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 fixe e.target à un navigateur croisé, ce qui rend inutile tout ce battage. :) –

+0

Tout cela est discutable si vous ne prenez en charge que IE9 +, il est maintenant corrigé http://msdn.microsoft.com/en-us/library/ie/ff974946%28v=vs.85%29.aspx – Gabe

Questions connexes