2012-06-01 13 views
13

Mit jQuery wie erkennt man Klicks nicht auf bestimmte Elemente, und führen Sie eine Aktion konsequent aus?Dokument klicken nicht in Elemente jQuery

Ich habe folgendes JavaScript

$('#master').click(function() { 
    $('#slave').toggle(); 
}); 

$(document).not('#master','#slave').click(function() { 
    $('#slave').hide(); 
}); 

und ich kann nicht sehen, wo ich falsch logisch werde. Sie können ein anschauliches Beispiel here

+1

Das Binden einer Instanz Ihres Klick-Handlers an jedes DOM-Element (mit Ausnahme von zwei) ist für die Leistung sehr schlecht. – jbabey

+1

Der Grund, warum Ihre Version nicht funktioniert, ist, dass Sie testen, ob das 'document' Element nicht 'master' oder 'slave' als ID hat. Dies ist immer wahr (IIRC 'Dokument' kann keine ID haben), so dass der Handler an das' Dokument' gebunden ist und jeder Klick bewirkt, dass 'Slave' ausgeblendet wird. Aufgrund der Ereignisausbreitung wird das 'click'-Ereignis von' #master' auf das 'Dokument' gesprengt, wo es' #slave' versteckt, obwohl '#master' es nur umgeschaltet hat. Sie müssen "event.target" testen, damit dies funktioniert. –

Antwort

32

sehen Da Sie auf das click Ereignis auf dem Dokument sind verbindlich, Sie event.target verwenden können, um das Element zu erhalten, das das Ereignis ausgelöst:

$(document).click(function(event) { 
    if (!$(event.target).is("#master, #slave")) { 
     $("#slave").hide(); 
    } 
}); 

EDIT: Als Mattias weist rechtmäßig in seinem Kommentar darauf hin, dass der obige Code keine Klickereignisse identifizieren kann, die von den Nachkommen von #master und #slave stammen (falls vorhanden). In dieser Situation können Sie closest() verwenden die Veranstaltungs-Ziel zu überprüfen:

$(document).click(function(event) { 
    if (!$(event.target).closest("#master, #slave").length) { 
     $("#slave").hide(); 
    } 
}); 
+1

Wenn '# master' oder' # slave' untergeordnete Elemente haben, müssen Sie 'engste' anstelle von' is' verwenden, damit diese Kinder funktionieren. –

+0

@ Mattias, sehr wahr. Antwort aktualisiert entsprechend, danke :) –

+0

Dies ist ein schlechter Ersatz für ['delegate'] (http://api.jquery.com/delegate), die bereits in jQuery implementiert ist. – zzzzBov

2

macht dieser Code, was Sie wollen? (Nicht ganz sicher, ob ich das richtig verstanden)

$('body').on('click', '*:not(#master, #slave)', function() { 
    $('#slave').hide(); 
}); 

http://jsfiddle.net/gZ4Hz/8/

1

Ein anderer Gedanke, kann es nicht funktioniert, weil Ihr Browser nicht body auf 100% Höhe Rendering werden kann; Versuchen Sie, Ihre Basis CSS zu korrigieren Körpergröße und dann ein paar andere Gedanken.

e.stopPropagation(): Verhindert, dass das Ereignis die DOM-Struktur aufblubbelt und verhindert, dass alle übergeordneten Handler über das Ereignis benachrichtigt werden.

Also, wenn Sie den ersten Klick ändern Code auf die folgenden:

$('#master').click(function(e) { 
    e.stopPropagation(); 
    $('#slave').toggle(); 
}); 

Auch dann könnte man das Rufzeichen des zweiten ändern:

$("body, body *").not('#master, #slave').click(function(e) { 
    $('#slave').hide(); 
}); 

Und das sollte es abdecken. Versuche es! oder siehe this jsFiddle

+0

Perfekt! Du hast mich gerade zu einem glücklichen Mann gemacht :) – jacktheripper

+1

Binding Event Handler zu allen anderen Elementen ist keine gute Idee. Frédéric Hamidis Lösung ist besser. –

+1

Das ist eine schreckliche Lösung. Sie binden diesen zweiten Handler separat an ** jedes einzelne Element im DOM **. Das ist nicht nur furchtbar ineffizient, es wird auch nicht mit dynamisch eingefügten Elementen funktionieren, die anschließend zum DOM hinzugefügt werden. Frédérics Lösung ist viel eleganter und (wichtiger) funktioniert in jeder Situation. –

2

Die Ereignisdelegierung wurde seit langem von jQuery nativ unterstützt. Die Schwierigkeit besteht darin, den entsprechenden Selektor zu erstellen. Ursprünglich wurde delegate verwendet, aber in jüngerer Zeit sollte die Delegiertenform von on verwendet werden.

Zweck der Ereignisdelegierung ist das Abhören von Ereignissen in untergeordneten Elementen und das Aufrufen der gebundenen Ereignisbehandlungsroutinen für diese Elemente, als ob sie an das untergeordnete Element statt an das übergeordnete Element gebunden wären. Dies bedeutet, dass anstelle des Bindens von Handlern an jedes -Element im DOM ein Handler an jedes Element in der ursprünglichen Auswahl gebunden wird (document ist ein einzelnes Element).Dies macht auch für eine einfache Möglichkeit, einen einzelnen Wähler zu verwenden, um einem sich ständig verändernden Satz von Elementen zu binden, als neue Elemente ihre Veranstaltungen zu document ausbreitet, ob sie bestanden, wenn die anfängliche Ereignishandler gebunden wurde:

$(document).on('click', '*:not(#master, #master *, #slave, #slave *)', function (e) { 
    //this will reference the clicked element 
}); 

Beachten Sie außerdem, dass ich nicht nur gesagt habe, dass die Elemente nicht #master oder #slave sein müssen, sie müssen nicht Kinder von #master oder #slave sein.

+0

Sehr interessant. Ich vermeide normalerweise '*' Selektoren sowohl in CSS (Kaskadierung ist die meiste Zeit ausreichend) und in jQuery (eine ganze Teilstruktur zu vergleichen kann teuer sein), aber ich stimme zu, sollte mindestens so gut funktionieren wie 'event.target' kombiniert 'nearest()' auf modernen Browsern. Jetzt bin ich neugierig auf die Perfs, vielleicht werde ich in meiner ausgiebigen Freizeit einen Benchmark setzen. Prost :) –

0

Fredriks Antworten funktionieren für Elemente, die bereits im Dokument vorhanden sind, aber es funktionierte nicht für Elemente, die von Ajax-Aufrufen abgerufen wurden. Ich habe folgendes versucht und es funktioniert für mich. Den Code für zukünftige Ajax-Programmierer freigeben.

$(document).on('click',function(event) { 
     if (!$(event.target).closest("#selector").length) { 
      if ($('#selector').is(":visible")) 
       $('#selector').slideUp(); 
     } 
    }); 

Ich hätte es als Kommentar gepostet, aber ich habe nicht genug Ruf dafür.

Verwandte Themen