2011-10-05 18 views
23

This answer indica quali elementi HTML possono ricevere lo stato attivo. C'è un selettore jQuery che corrisponde esattamente a questi elementi?C'è un selettore jQuery per ottenere tutti gli elementi che possono ottenere lo stato attivo?

Per ora sto usando solo $('input,select,textarea,a'), ma mi chiedo se c'è qualcosa di più preciso.

+0

Probabilmente no. Forse prova il selettore [': input'] (http://api.jquery.com/input-selector/)? – Bojangles

+0

Che cosa stai cercando di fare una volta che hai la lista degli elementi focalizzabili? – Dennis

+0

@Dennis - scorri verso il basso per assicurarti che siano visibili quando sono a fuoco. http://stackoverflow.com/questions/7650892/how-to-scroll-down-the-page-when-a-covered-input-box-is-focused – ripper234

risposta

5

Si potrebbe verificare la presenza di elementi che hanno la funzione di focus():

$('*').each(function() { 
    if(typeof this.focus == 'function') { 
    // Do something with this element 
    } 
}) ; 

Modifica Pensando un po 'di più, sarebbe probabilmente ha senso avere *:visible piuttosto che solo * come selettore per la maggior parte delle applicazioni di Questo.

+0

Decisamente la strada da percorrere. Non penso che sia possibile fino a quando i selettori espliciti vanno, dal momento che i selettori jQuery sono costruiti su http://sizzlejs.com. – ifightcrime

+0

eccetto, se si legge il post collegato nell'OP, si dice: 'gli unici elementi che hanno un metodo focus() sono HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement e HTMLAnchorElement. Questo in particolare omette HTMLButtonElement e HTMLAreaElement. Quindi testare per '.focus()' non lo farà (apparentemente). – Lee

+0

Gli elementi DOM sono oggetti host, non hanno bisogno di conformarsi alle regole di ECMAScript e quindi la loro risposta all'operatore * typeof * può essere qualsiasi cosa, incluso il lancio di un errore. In IE 8, 'typeof element.focus' restituisce * oggetto * su un input di testo, quindi il test sopra riportato fallirà nei circa 1: 5 browser in uso, possibilmente di più. – RobG

28

Dal other SO answer referred to by the OP:

i browser di oggi definiamo messa a fuoco() su HTMLElement, ...

Quindi, questo significa che il test per focus come membro del l'elemento è non efficace , perché tutti gli elementi lo avranno, indipendentemente dal fatto che accetti effettivamente lo stato attivo o meno.

... ma un elemento non sarà effettivamente prendere fuoco se non è uno dei seguenti:

  • HTMLAnchorElement/HTMLAreaElement con una href * HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement ma non con disabled (IE ti dà effettivamente un errore se lo provi), e gli upload di file hanno un comportamento insolito per motivi di sicurezza
  • HTMLIFrameElement (sebbene la messa a fuoco non faccia nulla di utile). Anche altri elementi di inclusione, forse, non li ho testati tutti.
  • Qualsiasi elemento con un tabindex

Quindi, che dire di nominare tutti coloro che in modo esplicito in un jQuery Selector?

$('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]') 

Update # 1:

I updated your jsFiddle here. Sembra funzionare.

Ho anche aggiunto elementi con l'attributo contenteditable all'elenco precedente.


Update # 2:

Come @ jfriend00 ha sottolineato, "a seconda dell'uso, uno potrebbe voler filtrare gli elementi che non sono visibili". Per fare ciò, è sufficiente applicare .filter(':visible') all'insieme generato dal selettore precedente.


Update # 3:

Come Xavin pointed out: jQuery UI ora ha un selettore, :focusable, che svolge questa funzione. Se stai già utilizzando l'interfaccia utente di jQuery, questa potrebbe essere la soluzione. In caso contrario, è possibile che si desideri check out how jQuery UI does it. In ogni caso, la descrizione nella pagina di jQuery UI per :focusable è utile:

Elementi del seguente tipo sono attivabile se non sono disabilitati: ingresso, selezionare, textarea, pulsante, e l'oggetto. Le ancore sono focalizzabili se hanno un attributo href o tabindex. gli elementi dell'area sono selezionabili se si trovano all'interno di una mappa denominata, hanno un attributo href e c'è un'immagine visibile utilizzando la mappa. Tutti gli altri elementi sono focalizzabili esclusivamente in base all'attributo e alla visibilità del tabindex.

Così, il selettore ho proposto sopra è vicino, ma non riesce a tenere conto di alcune sfumature.

Ecco la funzione strappata dall'interfaccia utente di jQuery, con piccoli adattamenti per renderla autonoma. (Gli adattamenti sono testati, ma dovrebbe funzionare):

function focusable(element) { 
    var map, mapName, img, 
     nodeName = element.nodeName.toLowerCase(), 
     isTabIndexNotNaN = !isNaN($.attr(element, "tabindex")); 
    if ("area" === nodeName) { 
     map = element.parentNode; 
     mapName = map.name; 
     if (!element.href || !mapName || map.nodeName.toLowerCase() !== "map") { 
      return false; 
     } 
     img = $("img[usemap=#" + mapName + "]")[0]; 
     return !!img && visible(img); 
    } 
    return (/input|select|textarea|button|object/.test(nodeName) ? 
     !element.disabled : 
     "a" === nodeName ? 
      element.href || isTabIndexNotNaN : 
      isTabIndexNotNaN) && 
     // the element and all of its ancestors must be visible 
     visible(element); 

    function visible(element) { 
     return $.expr.filters.visible(element) && 
     !$(element).parents().addBack().filter(function() { 
      return $.css(this, "visibility") === "hidden"; 
     }).length; 
    } 
} 

Nota: la funzione di cui sopra dipende ancora jQuery, ma non dovrebbe richiedere jQuery UI.

+0

A seconda dell'utilizzo, è possibile filtrare elementi non visibili. – jfriend00

+0

Forse non esiste un modo migliore, ma il problema con questo tipo di codice è che è fragile. Dovrà essere mantenuto ogni volta che c'è un nuovo tipo di elemento modificabile o un nuovo attributo che rende qualcosa modificabile. – jfriend00

+0

@ jfriend00 - buon punto. Ho aggiornato la mia risposta per includere il tuo suggerimento. – Lee

0

Invece di ottenere un elenco di elementi attivabili, è possibile provare a impostare un gestore di messa a fuoco sull'elemento body che acquisisce gli eventi di messa a fuoco.

$(document.body).on("focus", "*", function(e) { 
    //Scroll to e.target 
}); 
+4

Tranne che abbiamo dimostrato che il controllo del tipo di 'this.focus' non funziona. – jfriend00

4

Un altro semplice, ma completo, selettore jQuery potrebbe essere questa:

$('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]') 
.not('[tabindex=-1], [disabled], :hidden') 
+1

il '*' davanti a '[tabindex]' non è necessario – Omu

+0

Sì, hai ragione! – tzi

0

Ho una soluzione relativamente semplice che restituisce tutti i bambini tabbable, nel loro ordine di tabulazione, senza l'utilizzo di jQuery.

function tabbable(el) { 
    return [].map.call(el.querySelectorAll([ 
     'input', 
     'select', 
     'a[href]', 
     'textarea', 
     'button', 
     '[tabindex]' 
    ]), function(el, i) { return { el, i } }). 
     filter(function(e) { 
      return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }). 
     sort(function(a,b) { 
      return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); }); 
} 

Per IE, considerare l'implementazione di un controllo di visibilità diverso rispetto a e.el.offsetParent. jQuery può aiutarti qui.

Se non sono necessari gli elementi ordinati, lasciare la chiamata a sort().

Problemi correlati