2010-02-03 10 views
6

Ich bin auf der Suche nach der Logik, um eine Dropdown-Menü-Tastatur zugänglich zu machen.jQuery herauszufinden, ob das Elternteil "Fokus" verloren hat

Die HTML wird als solche (extra Klassennamen für Klarheit verwendet) strukturiert:

<ul> 
    <li class="primaryMenuItem"> 
     <a href="">Link 1</a> 
     <ul class="popUpMenu"> 
      <li><a href="">Sub Link 1</a></li> 
      <li><a href="">Sub Link 2</a></li> 
     </ul> 
    </li> 
    <li class="primaryMenuItem"> 
     <a href="">Link 2</a> 
     <ul class="popUpMenu"> 
      <li><a href="">Sub Link 1</a></li> 
      <li><a href="">Sub Link 2</a></li> 
     </ul> 
    </li>  
</ul> 

Verbindung 1 und Link 2, wenn schwebte, wird das Untermenü Listen zeigen (Pull-Down-Menü). Ich habe das funktioniert gut mit einigen jQuery und dem jQuery HoverIntent-Plugin.

Der Haken ist, dass dies zur Zeit nur mit der Maus funktioniert.

Die nächste Herausforderung besteht darin, dies über die Tastatur zu erledigen.

Ich kann leicht ein Fokus-Ereignis auf die Top-Level-Links hinzufügen, die dann die sekundären Menüs auslösen:

$('ul.primaryMenuItem a:first').focus([call showMenu function]) 

Das funktioniert gut.

Um das Menü zu schließen, müssen Sie beim Öffnen eines anderen Menüs prüfen, ob bereits ein anderes geöffnet ist, und falls ja, schließen Sie es.

Das funktioniert auch gut.

Wo das jedoch fehlschlägt, ist, wenn Sie das letzte Menü geöffnet haben, und Tab daraus. Da Sie nicht in ein anderes Menü getippt haben, bleibt dieses geöffnet.

Die Herausforderung besteht darin herauszufinden, wie/wann das Menü zu schließen ist und welche Logik (jQuery) benötigt wird, um es herauszufinden. Im Idealfall würde ich das Menü schließen, wenn der Fokus auf einem Element auf der Seite ANDERER als die untergeordneten Elemente des Menüs liegt.

Logisch, ich bin für diese Suche:

$('li.primaryMenuItem').blur([close $(this).find('ul.popUpMenu')) 

Allerdings können Sie das nicht tun, da die LI eigentlich nicht im Fokus hat, sondern den Anker-Tag in sie.

Irgendwelche Vorschläge?

UPDATE:

vielleicht ein besserer/einfacherer Weg, um die Frage zu stellen:

Via jQuery, ist es eine Möglichkeit, zu ‚Uhr‘, um zu sehen, wenn der Fokus außerhalb aller Kinder eines bestimmten Objekts bewegt hat ?

+0

Gibt es ein Tippfehler? '$ ('ul.primaryMenuItem a: first'). focus ([Aufruf showMenu Funktion])' -> '$ ('li.primaryMenuItem a: first'). focus ...' – superjos

Antwort

2

Verwenden Sie die neuen jquery 1.4-Funktionen: focusin und focusout anstelle von blur und focus. Hier ist, wie focusout unterscheidet:

Das focusout Ereignis an ein Element gesendet wird, wenn es oder jedes Element innerhalb davon, den Fokus verliert. Dies ist unterscheidbar aus dem Blur-Ereignis, dass es unterstützt Erkennung der Verlust des Fokus von übergeordneten Elementen (mit anderen Worten, unterstützt Ereignisse sprudeln).

+0

@Keltex Ich schaute mir das an . Aber das brauche ich nicht. Ich möchte wissen, ob der Elterncontainer den Fokus verloren hat. Focusout wird ausgelöst, wenn eines der untergeordneten Elemente den Fokus verliert. Dies bedeutet, dass das Tabbing vom Untermenü zum Untermenü dieses Ereignis auslösen würde. Ich brauche etwas in der Art von "hat die Person, die außerhalb des Containertasters getaggt ist". –

0

diesen Logischer

$('li.primaryMenuItem:last li a:last').blur([do whatever you need to do]) 

Versuchen Sie, wenn Sie Ihren Benutzer Tabs heraus, dass er den letzten Anker konzentriert worden sein.

Sie sogar Ihre eigenen Event-Handler wie so eingerichtet könnte:

$('li.primaryMenuItem:last').bind('myblur', function() ...); 

und es innerhalb der letzten Anker Unschärfe Ereignis nennen:

...blur(function() { 
    $(this).parents('li.primaryMenuItem').trigger('myblur'); ... 
+0

Das Problem damit besteht darin, dass es viele Möglichkeiten gibt, das Menü zu verlassen, bevor das letzte Element aus dem Register gezogen wird. Zum Beispiel könnten Sie rückwärts Tabstopps ausführen, was bedeutet, dass Sie den letzten Eintrag abwählen können, aber immer noch im selben Menü sind. Zusätzlich könnte man einen Tastaturbefehl oder einen Mausklick verwenden, um während der Hälfte des Menüs zu verschwimmen. –

6

Sie können Ereignis zu überprüfen, sprudeln, was den Fokus hat auf das fokussierende Ereignis. Ich hatte Erfolg mit dem folgenden Code:

Sie könnten (sollte) wahrscheinlich machen es mehr optimiert, aber es funktioniert.

+0

Interessant! Ich fühle mich jedoch merkwürdig, wenn ich einen Event-Handler an den Body und alle Kind-Elemente angehängt habe. Gibt es irgendeine Art von Performance-Problem dabei? Letztlich ist Ihre Lösung "auf jeden Fokus, sehen Sie, ob es in der Speisekarte ist. Wenn nicht, schließe es. Was sicherlich Sinn macht. –

+0

Nun, es wird die focusin Ereignis jederzeit auslösen ein Fokus-Ereignis innerhalb des Körpers auftritt, aber Fokus in der Regel nicht sehr schnell ändern, und wird es eine begrenzte Anzahl von Elementen, die das Ziel eines Fokus-Ereignis sein kann (links/Formelemente) Ich persönlich denke nicht, dass das Aufrufen dieses Vergleichs bei jedem Fokusereignis die Leistung zu sehr beeinflussen wird. Sie könnten versuchen, den Vergleich zu optimieren (ich bin mir nicht sicher, was schneller ist $ (e.target) .is ('ul.popUpMenu li a') oder Beispiel), und Sie sollten die Element-Abfrage zwischenspeichern. Wenn Leistung ein echtes Problem ist, müssen Sie einige Benchmarks ausführen, um die Auswirkungen zu überprüfen. – emmychan

+2

FocusIn wird in einigen Browsern für das Body-Tag (oder viele andere Tags) nicht ausgelöst. Den Tabindex auf -1 zu setzen, scheint das zu beheben und macht diese Lösung zu einer guten Anpassung - $ ("body"). Attr ("tabindex", -1); – John

0

Das bin ich ... http://plugins.jquery.com/project/focus

half

Es erkennt, ob Sie automatisch noch im Elternteil sind. Grundsätzlich ändert sich jQuery focusout so, dass es auf diese Weise funktioniert, was meiner Meinung nach so ist, wie es funktionieren sollte.

<div class="parent"> 
    <input type="text" /> 
    <input type="text" /> 
</div> 

$('#parent').focusout(function() { 
    console.log('focusout of parent'); 
}); 

Ich sehe nicht, warum das Drücken der Tabulatortaste zwischen Textfeld der untergeordneten Elementen zu bewegen, sollte auf den Eltern auslösen focusout, weil Sie noch innerhalb dieses Elternteil sind. Irgendetwas muss passieren, dass dich für einen Moment raus bringt und ich vermute es ist ein Käfer ... irgendjemand mit mir dabei? Nun, das obige Plugin behebt das Problem. Fügen Sie es einfach vor Ihrem Code ein, um das Problem zu beheben. Würde jemanden lieben zu erklären, warum dies kein Fehler ist, wenn es nicht ist.

Danke, Dom

2

Wie wäre es, wenn Sie wie folgt vorgehen:

$('#link_A_id, #link_A_id > *').focusout(function() { 
    if ($(document.activeElement).closest('#link_A_id').length == 0) 
     //focus is out of link A and it's children 
}); 
+0

+1 Das brachte mich in die richtige Richtung. Ich sehe nicht, warum der zweite Selektor ('#link_A_id> *') benötigt wird und ich ihn nicht benutzt habe. Ich musste auch die if-Anweisung in ein Timeout umbrechen, weil das 'body'-Element * den Fokus stiehlt *, bevor das nächste Element den Fokus erhält. – toxalot

0

ich ein ähnliches Problem hatte ... Ich habe eine jsfiddle erstellt, um zu bestimmen, wenn ein Elternteil Fieldset den Fokus verliert und dann ein Aufruf Funktion. Es könnte sicherlich optimiert werden, aber es ist ein Anfang.

http://jsfiddle.net/EKhLc/10/

function saveFields() { 
    $.each($('fieldset.save'),function(index, value) { 
    // WHERE THE POST WOULD GO 
    alert('saving fieldset with id '+ value.id); 
    $(value).removeClass('save'); 
    }); 

} 
$('.control-group').focusin(function(){ 
    var thefield = $(this).parent('fieldset'); 
    if (!thefield.hasClass('active')) { 
    if($('fieldset.active').length > 0){ 

     $('fieldset.active').removeClass('active').addClass('save'); 
     saveFields(); 
     } 
    thefield.addClass('active'); 
    } else { 
     console.log('already active'); 
    } 
});