jQuery bind click * ALLES * aber * ELEMENT *

72

Angenommen, es schweben einige Elemente herum, und ich versuche, einige zu tun, wenn ich auf ALLES klicke (divs, body, was auch immer ...), aber auf das angegebene (z. B. div # special).

Ich frage mich, ob es neben der folgenden Methode, die mir einfällt, einen besseren Weg gibt, dies zu erreichen ...

$(document).bind('click', function(e) {
    get mouse position x, y
    get the element (div#special in this case) position x, y
    get the element width and height
    determine if the mouse is inside the element
    if(inside)
        do nothing
    else
        do something
});
railOne
quelle
3
Mögliches Duplikat von Wie erkennt man einen Klick außerhalb eines Elements?
Felix Kling
$(':not(div#special)').bind('click', function(e) { ...? api.jquery.com/not-selector
Jim Schubert
@ JimSchubert: Sollte es funktionieren, würde ich es als Antwort posten - es ist einfacher als die Antworten im möglichen Duplikat. Es scheint jedoch ineffizient.
Wesley Murch
1
@ Wesley: Aber es ist nicht richtig. Der Event-Handler wird auch an Elemente im Inneren gebunden sein div#special...
Felix Kling
4
@ Jim: :not(div#special, div#special *)wäre richtig. Ich würde jedoch vermeiden, einen Ereignishandler an jedes Element zu binden . In diesem Fall ist die Verwendung der Ereignisdelegierung viel besser.
Felix Kling

Antworten:

118

Um die Situation "Dies tun, außer wenn auf dieses Element geklickt wird" zu behandeln, besteht der allgemeine Ansatz darin, dem Ereignis document"Dies tun" einen Ereignishandler hinzuzufügen und dann dem Element "Außer diesem" einen weiteren Ereignishandler hinzuzufügen verhindert, dass das Klickereignis bis zum sprudelt document;

$('#special').on('click', function(e) {
    e.stopPropagation();
});

$(document).on('click', function (e) {
 // Do whatever you want; the event that'd fire if the "special" element has been clicked on has been cancelled.
});

Siehe die event.stopPropagation()Dokumentation . Für diejenigen unter Ihnen, die Versionen vor jQuery 1.7 verwenden (wie es der Fall war, als diese Frage gestellt wurde), können Sie diese nicht verwenden on(). stattdessen einfach die 2 Verwendungen von on()durch ersetzen bind(); Die Unterschrift ist in diesem Fall dieselbe.

Demo hier; http://jsfiddle.net/HBbVC/

Matt
quelle
6
Nichts für ungut, aber das ist im Grunde die gleiche Antwort wie in dem Duplikat, mit dem ich verlinkt habe: stackoverflow.com/questions/152975/…
Felix Kling
4
@ Felix: Ich kann das jetzt sehen, aber Sie hatten den Kommentar nicht gepostet, als ich anfing, die Antwort zu schreiben :(.
Matt
scheint auf mobiler Safari nicht zu funktionieren, obwohl ich nirgendwo anders Probleme habe.
Dgig
Ihre Antwort in Kombination mit der Antwort von Hugo Silva hier hat mein spezielles Problem bei Safari behoben. Mobile lässt nicht immer eine "Klick" -Aktion auf Nicht-Anker zu, daher müssen Sie sie anscheinend definieren (siehe seine Antwort für eine angemessene Erklärung): stackoverflow.com/questions/10722730/…
dgig
Dies funktioniert nicht, wenn Ereignishandler definiert sind, die auf andere Elemente abzielen, die ein Sprudeln verhindern. Dies führt dazu, dass diese Elemente als falsch positiv eingestuft werden. Imho, eine bessere / vollständig sichere Lösung besteht darin, einen Dokumentenhandler (wie erledigt) zu definieren, ihn jedoch so zu definieren, dass er in der Erfassungsphase anstatt in der Blasenphase ausgelöst wird . Sie müssten im Handler aktiv filtern, welche Elemente Sie überspringen / durchlassen möchten. Sie können den anderen Handler weglassen.
Geert-Jan
46

Sie könnten auch tun

$(document).bind('click', function(e) {
  if(!$(e.target).is('#special')) {
    // do something
  }
});

oder wenn div # special untergeordnete Elemente hat, können Sie dies tun

$(document).bind('click', function(e) {
  if($(e.target).closest('#special').length === 0) {
    // do something
  }
});
bmavity
quelle
5

Ich habe es in der Vergangenheit so gemacht:

jQuery("body").bind("click", function(e)
{
    var obj = (e.target ? e.target : e.srcElement);
    if (obj.tagName != 'div' && obj.id != 'special')
    {
        // Perform your click action. 
        return false;
    }
});

Dies würde nur ausgeführt, wenn Sie nicht auf div # special klicken. Ehrlich gesagt gibt es vielleicht bessere Möglichkeiten, aber das hat bei mir funktioniert.

Dan Smith
quelle
2
Sie müssen nicht testen e.target. Es wird immer da sein, jQuery normalisiert das Ereignisobjekt. Und es wird nicht funktionieren, wenn es div#specialandere Elemente enthält.
Felix Kling
1

Sie müssen verschiedene Bindungen ausführen. Es ist nicht erforderlich, alle diese Klicks in einer Funktion zu verarbeiten

$('body').bind('click', function(e){
  bodyClickEvent();
});
$('div.floating').bind('click',function(e){
  elementClickEvent(this);
  e.stopPropagation(); //prevents bodyClickEvent
});
  $('div#special').bind('click', function(){
  e.stopPropagation(); //prevents bodyClickEvent
});
El '
quelle
1

Ich habe dies heute für ein Problem geschrieben, das ich hatte, da ich es nicht mag, wenn Klickereignisse die ganze Zeit an das Dokument gebunden sind. In meinem Szenario funktioniert dies mit Rückrufen von Funktionen.

$('#button').click(function(){
        //when the notification icon is clicked open the menu
        $('#menu').slideToggle('slow', function(){
            //then bind the close event to html so it closes when you mouse off it.
            $('html').bind('click', function(e){
                $('#menu').slideToggle('slow', function(){
                    //once html has been clicked and the menu has closed, unbind the html click so nothing else has to lag up
                    $('html').unbind('click');
                });
            });
            $('#menu').bind('click', function(e){
                //as when we click inside the menu it bubbles up and closes the menu when it hits html we have to stop the propagation while its open
                e.stopPropagation();
                //once propagation has been successful! and not letting the menu open/close we can unbind this as we dont need it!
                $('#menu').unbind('click');
            });
        });
    });
Owen
quelle
0

Ich habe das einmal etwas einfacher gelöst als die anderen Antworten, ohne darauf zu achten, dass das Klicken wirklich den DOM-Baum hinuntergeht

überprüfe einfach, ob dein Element schwebt;)

$(document).on('click', function (e) {

  if($('#special:hover').length > 0){
    // on our special element
  }else{
    // not on our special element
  }

});

Prost

John Smith
quelle