Hangi DOM öğesinin odağı olduğunu nasıl öğrenebilirim?


1309

JavaScript'te hangi öğenin şu anda odağa sahip olduğunu öğrenmek istiyorum. DOM'u inceledim ve ihtiyacım olanı henüz bulamadım. Bunu yapmanın bir yolu var mı ve nasıl?

Bunu aramamın nedeni:

Oklar gibi anahtarlar yapmaya ve entergiriş elemanlarının bir tablosunda gezinmeye çalışıyorum . Sekme şimdi çalışıyor, ancak enter ve oklar varsayılan olarak görünmüyor. Anahtar işleme parçasını ayarladım, ancak şimdi olay işleme işlevlerinde odağı nasıl hareket ettireceğimizi bulmam gerekiyor.


2
Burada console.log'a odaklanılan öğeyi kaydeden bir yer işareti: github.com/lingtalfi/where-is-focus-bookmarklet
ling

find-focused-elementPaketi kullanabilirsiniz : npmjs.com/package/find-focused-element
Maxim Zhukov

Yanıtlar:


1533

Kullanımı document.activeElement, tüm büyük tarayıcılarda desteklenir.

Önceden, hangi form alanının odaklandığını bulmaya çalışıyorsanız, yapamazdınız. Daha eski tarayıcılarda algılamayı taklit etmek için, tüm alanlara bir "odak" olay işleyicisi ekleyin ve son odaklı alanı bir değişkene kaydedin. Son odaklanan alan için bir bulanıklaştırma olayında değişkeni temizlemek için bir "bulanıklaştırma" işleyicisi ekleyin.

Eğer kaldırmak gerekiyorsa activeElementbulanıklık kullanabilirsiniz; document.activeElement.blur(). Bu değişecek activeElementTo body.

İlgili Bağlantılar:


53
IE hakkında emin değilim, ancak FF ve Safari'nin her ikisi de BODY öğesini döndürüyor.
JW.

10
activeElementaslında odaklanmış öğeyi döndürmez. Herhangi bir öğenin odağı olabilir. Bir belgede 4 'kaydırma çubuğu' varsa, bu bölmelerin 0 veya 1'i ok tuşları ile kaydırılabilir. Birini tıklatırsanız, bu div odaklanır. Her şeyin dışına tıklarsanız, vücut odaklanır. Hangi scrolldiv'in odaklandığını nasıl öğrenirsiniz? jsfiddle.net/rudiedirkx/bC5ke/show (kontrol konsolu)
Rudie

18
@Rudie, @Stewart: Daha ayrıntılı bir oyun alanı oluşturmak için kemanın üzerine inşa ettim: jsfiddle.net/mklement/72rTF . Aslında böyle bir odaklanabilen tek büyük tarayıcının (2012 sonu itibariyle) divFirefox 17 olduğunu ve sadece sekmesini kullanarak göreceksiniz . TÜM büyük tarayıcıların döndürdüğü öğe türleri girişle ilgili öğelerle document.activeElementsınırlıdır . Böyle bir öğenin odağı yoksa, tüm büyük tarayıcılar öğeyi döndürür - öğeyi döndüren IE 9 hariç . bodyhtml
mklement0

10
Bunun yardımcı olup olmadığından emin değilim, ancak tabindex = "0" niteliğini ekleyerek div alma klavye odağı gibi bir öğe yapabilirsiniz
Marco Luglio

4
Herhangi bir erişim bazı durumlarda bir istisna (sadece IE9 AFAIK değil) atabilir gibi document.activeElementsarılmalıdır try catch. Bkz. Bugs.jquery.com/ticket/13393 ve bugs.jqueryui.com/ticket/8443
robocat

127

JW tarafından söylendiği gibi, mevcut odaklanmış öğeyi en azından tarayıcıdan bağımsız bir şekilde bulamazsınız. Ancak uygulamanız yalnızca IE ise (bazıları ...), şu şekilde bulabilirsiniz:

document.activeElement

DÜZENLEME: Görünüşe göre IE'de her şey yanlış değildi, bu HTML5 taslağının bir parçası ve en azından Chrome, Safari ve Firefox'un en son sürümü tarafından destekleniyor gibi görünüyor.


5
FF3 de. Bu aslında "odak yönetimi" etrafındaki HTML5 spesifikasyonunun bir parçasıdır.
Crescent Fresh

2
Chrome ve Opera'nın (9.62) geçerli sürümünde çalışır. OS
3.2'de

krom 19 için hala aynı: S
Sebas

1
Öğeye sekmek için klavyeyi kullandığınızda yalnızca krom (20) / safari (5.1.3) içinde çalışır. Üzerine tıklarsanız ne jquery: focus selector ne de document.activeElement tıklattığınız öğeyi döndürmeyi başaramaz (sırasıyla tanımsız ve belge gövdesi öğesini döndürme). PS Bu konu 2 yaşında olduğuna inanamıyorum ve hala atlama bağlantıları çalışmıyor bir webkit üzerinde hala regresyon sorunları vardır, ama deneysel css3 ekleyerek çok fazla iş yapılıyor. Aileme ve arkadaşlarıma firefox tavsiye etmeye geri dönebileceğimi düşün.
Dawn

^^ document.activeElement, bir metin alanına veya başka bir girdiye odaklanmak için tıkladığınızda iyi durumda. Bir bağlantıysa, tıklandığında odaklanmayacaktır (sayfada veya açıkçası).
marksyzm

84

JQuery kullanabiliyorsanız, artık destekliyor: odak, sadece 1.6 ve sonraki sürümleri kullandığınızdan emin olun.

Bu ifade size şu anda odaklanmış öğeyi getirecektir.

$(":focus")

Kimden: jQuery ile üzerine odaklanan bir öğeyi seçme


4
Bu iyi, ama jQuery nasıl yapıyor? document.activeElement? Bunu buldum: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
Harry Pehkonen

46

document.activeElementartık HTML5 çalışma taslağı belirtiminin bir parçasıdır , ancak bazı büyük olmayan / mobil / eski tarayıcılarda henüz desteklenmiyor olabilir. Adresine geri dönebilirsiniz querySelector(destekleniyorsa). Tarayıcı penceresine odaklanmasa bile, hiçbir öğe odaklanmazsa document.activeElementgeri döneceğini belirtmek document.bodygerekir.

Aşağıdaki kod bu soruna geçici bir çözüm getirecek ve querySelectorbiraz daha iyi destek vermeye geri dönecektir .

var focused = document.activeElement;
if (!focused || focused == document.body)
    focused = null;
else if (document.querySelector)
    focused = document.querySelector(":focus");

Dikkat edilmesi gereken bir diğer nokta da bu iki yöntem arasındaki performans farkıdır. Belgeyi seçicilerle sorgulamak her zaman activeElementözelliğe erişmekten çok daha yavaş olacaktır . Bu jsperf.com testine bakın .


21

Tek başına, document.activeElementbelge odaklanmamışsa (ve böylece belgedeki hiçbir şey odaklanmazsa) bir öğeyi döndürebilir !

Sen olabilir davranışı istemek, ya da olabilir önemli değil (örneğin bir mesafede keydownolay), ama aslında odaklanmış bir şeyler bilmek gerekiyorsa, fazladan kontrol edebilirsiniz document.hasFocus().

Aşağıdakiler, varsa odaklanmış öğeyi verecektir null.

var focused_element = null;
if (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
) {
    focused_element = document.activeElement;
}

Belirli bir öğenin odaklanıp odaklanmadığını kontrol etmek için daha basit:

var input_focused = document.activeElement === input && document.hasFocus();

Bir şeyin odaklanıp odaklanmadığını kontrol etmek için tekrar daha karmaşıktır:

var anything_is_focused = (
    document.hasFocus() &&
    document.activeElement !== null &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement
);

Bozulmazlık Not : Bu kontroller karşı kodunda document.bodyve document.documentElementbazı tarayıcılar Bunlardan birini iade çünkü ya, bu nullhiçbir şey odaklandığında.

Bu eğer dikkate almaz <body>(ya da belki <html>) bir vardı tabIndexdolayısıyla niteliği ve aslında odaklanmış olabilir . Bir kütüphane ya da başka bir şey yazıyorsanız ve sağlam olmasını istiyorsanız, muhtemelen bunu bir şekilde ele almalısınız.


İşte odaklanmış öğeyi almanın ( ağır hava tırnakları) "tek astarlı" bir versiyonu, bu da kısa devre hakkında bilgi sahibi olmanız gerektiğinden kavramsal olarak daha karmaşıktır ve biliyorsunuz, açıkçası bir çizgiye uymuyor, okunabilir olmasını istiyorum.
Bunu tavsiye etmeyeceğim. Ama eğer 1337 hax0r, idk ... orada. Bazı durumlarda almayı sakıncası yoksa
da || nullparçayı çıkarabilirsiniz false. (Hala alabilir nulleğer document.activeElementolduğunu null):

var focused_element = (
    document.hasFocus() &&
    document.activeElement !== document.body &&
    document.activeElement !== document.documentElement &&
    document.activeElement
) || null;

Belirli bir öğenin odaklanmış olup olmadığını kontrol etmek için, alternatif olabilir olayları kullanabilirsiniz, ancak bu şekilde kurulum gerektirir (ve potansiyel olarak söküm) ve önemlisi bir ilk devlet varsayar :

var input_focused = false;
input.addEventListener("focus", function() {
    input_focused = true;
});
input.addEventListener("blur", function() {
    input_focused = false;
});

İlk durum varsayımını olaysız yolu kullanarak düzeltebilirsiniz, ancak bunun yerine bunu da kullanabilirsiniz.


15

document.activeElement<body>odakta odaklanabilir öğe yoksa varsayılan olarak öğeye dönebilir. Ayrıca, bir öğeye odaklanılırsa ve tarayıcı penceresi bulanıksa, activeElementodaklanılan öğeyi tutmaya devam eder.

Bu iki davranışlardan biri arzu değilseniz, CSS tabanlı bir yaklaşım göz önünde bulundurun: document.querySelector( ':focus' ).


Harika, evet benim durumumda yaklaşımınız kesinlikle mantıklıydı. Odaklanabilir öğelerimi 'tabindex = "- 1"' ile ayarlayabilirim, eğer hiçbiri odaklanmıyorsa (diyelim ki, umurumda olmayan bazı metin veya resim) .querySelector (': focus') döndürür boş.
Manfred

Kullanmamak için cevabımı görün querySelector: stackoverflow.com/a/40873560/2624876
1j01

10

Joel S tarafından kullanılan yaklaşımı beğendim, ama aynı zamanda sadeliğini de seviyorum document.activeElement. JQuery kullandım ve ikisini birleştirdim. Desteklemeyen eski tarayıcılar 'hasFocus' değerini saklamak için document.activeElementkullanılır jQuery.data(). Daha yeni tarayıcılar kullanacaktır document.activeElement. Bunun document.activeElementdaha iyi bir performansa sahip olacağını düşünüyorum.

(function($) {
var settings;
$.fn.focusTracker = function(options) {
    settings = $.extend({}, $.focusTracker.defaults, options);

    if (!document.activeElement) {
        this.each(function() {
            var $this = $(this).data('hasFocus', false);

            $this.focus(function(event) {
                $this.data('hasFocus', true);
            });
            $this.blur(function(event) {
                $this.data('hasFocus', false);
            });
        });
    }
    return this;
};

$.fn.hasFocus = function() {
    if (this.length === 0) { return false; }
    if (document.activeElement) {
        return this.get(0) === document.activeElement;
    }
    return this.data('hasFocus');
};

$.focusTracker = {
    defaults: {
        context: 'body'
    },
    focusedElement: function(context) {
        var focused;
        if (!context) { context = settings.context; }
        if (document.activeElement) {
            if ($(document.activeElement).closest(context).length > 0) {
                focused = document.activeElement;
            }
        } else {
            $(':visible:enabled', context).each(function() {
                if ($(this).data('hasFocus')) {
                    focused = this;
                    return false;
                }
            });
        }
        return $(focused);
    }
};
})(jQuery);

3
Bu, @William Denniss's ile değiştirilebilir $("*:focus")mi?
Pylinux

Sanırım yapabilirdi. Bunu uzun zaman önce yazdım ve şimdi 5 yıl sonra daha iyi bir çözümü tekrar gözden geçirmek için hiçbir nedenim yoktu. Denemek! Ben de aynısını yapabilirim. Sitemizde daha az eklenti var! :)
Jason

10

Mootools'ta bu amaçlar için kullandığım küçük bir yardımcı:

FocusTracker = {
    startFocusTracking: function() {
       this.store('hasFocus', false);
       this.addEvent('focus', function() { this.store('hasFocus', true); });
       this.addEvent('blur', function() { this.store('hasFocus', false); });
    },

    hasFocus: function() {
       return this.retrieve('hasFocus');
    }
}

Element.implement(FocusTracker);

Eleman ile odağı varsa kontrol edebilirsiniz Bu şekilde el.hasFocus()sağlanan startFocusTracking()verilen elemana anılmıştır.


7

JQuery, :focusgeçerli olarak sözde sınıfı destekliyor . JQuery belgelerinde arıyorsanız, sizi W3C CSS belgelerine yönlendiren "Seçiciler" bölümüne bakın . Chrome, FF ve IE 7+ ile test yaptım. IE'de çalışması <!DOCTYPE...için html sayfasında bulunması gerektiğini unutmayın. Odağı olan öğeye bir kimlik atadığınızı varsayan bir örnek:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});

1
Sen olmalıdır (her zaman?) Kullanımı this.idyerine $(this).attr('id')(eğer jQuery nesnesi sahip Allready olduğunda) ya da en azından $(this)[0].id. Bu düzeydeki yerel Javascript YOL daha hızlı ve daha verimlidir. Bu durumda fark edilmeyebilir, ancak sistem çapında bir fark göreceksiniz.
Martijn

7

Örneği olan bir nesneyi almak Elementistiyorsanız, kullanmalısınız document.activeElement, ancak örneği olan bir nesneyi almak istiyorsanız Text, kullanmalısınız document.getSelection().focusNode.

Umarım yardımcı olur.


Hangi açıdan daha iyi?
1j01

Tarayıcınızın denetçisini açın, sayfanın herhangi bir yerini tıklayın, bunu geçin document.getSelection().focusNode.parentElementve Enter'a dokunun. Bundan sonra, geçmiş document.activeElementve bir şeyler yapın. ;)
rplaurindo

Bu yorum kutusu odaklanmış ile document.activeElementverir <textarea>oysa document.getSelection().focusNodeverir <td>içerdiğini <textarea>(ve document.getSelection().focusNode.parentElementverir <tr>içeren <td>)
1j01

Özür dilerim, özür dilerim. İyi açıklamamıştım. Örneği olan bir nesneyi almak istiyorsanız Element, kullanmanız gerekir document.activeElement, ancak örneği olan bir nesneyi almak istiyorsanız Text, kullanmanız gerekir document.getSelection().focusNode. Lütfen tekrar test edin. Umarım yardımcı olmuşumdur.
rplaurindo

2
Soru, şu anda hangi öğenin odaklandığını sormaktır. Ve focusNodebir metin düğümü olduğu da garanti edilmez.
1j01

6

Document.activeElement kullanımı ile ilgili olası sorunlar var. Düşünmek:

<div contentEditable="true">
  <div>Some text</div>
  <div>Some text</div>
  <div>Some text</div>
</div>

Kullanıcı bir iç bölüme odaklanırsa, document.activeElement yine dış bölüme başvurur. İç div'lardan hangisinin odaklanacağını belirlemek için document.activeElement öğesini kullanamazsınız.

Aşağıdaki işlev bu sorunu çözer ve odaklanan düğümü döndürür:

function active_node(){
  return window.getSelection().anchorNode;
}

Odaklanmış öğeyi almayı tercih ediyorsanız, şunu kullanın:

function active_element(){
  var anchor = window.getSelection().anchorNode;
  if(anchor.nodeType == 3){
        return anchor.parentNode;
  }else if(anchor.nodeType == 1){
        return anchor;
  }
}

3
Bu gerçekten bir sorun değil document.activeElement: sözde sınıfı görünür bir şeye <div>ayarlayarak görsel olarak görebileceğiniz gibi iç öğeler aslında odaklanamıyor :focus(örnek: jsfiddle.net/4gasa1t2/1 ). Bahsettiğiniz şey, iç kısımlardan <div>hangisinin ayrı bir sorun olan seçim veya düzeltme işareti içerdiğidir.
Tim Down

6

Şu anda hangi öğenin odağa sahip olduğunu belirlemeye çalışırken aşağıdaki snippet'i yararlı buldum. Aşağıdakileri tarayıcınızın konsoluna kopyalayın ve her saniye odaklanılan geçerli öğenin ayrıntılarını yazdıracaktır.

setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);

console.logTüm öğeyi yazdırmak öğeyi tam olarak belirlemenize yardımcı olmazsa, tam öğeyi tam olarak belirlemenize yardımcı olmak için farklı bir şeyi kapatmak üzere değişiklik yapmaktan çekinmeyin .


5

Diğer cevapları okumak ve kendimi denemek, document.activeElementçoğu tarayıcıda ihtiyacınız olan öğeyi verecek gibi görünüyor .

JQuery'niz varsa document.activeElement öğesini desteklemeyen bir tarayıcınız varsa, bunu tüm odak olaylarında bunun gibi çok basit bir şeyle doldurabilmelisiniz (elimde bu kriterleri karşılayan bir tarayıcım olmadığı için test edilmemiştir) ):

if (typeof document.activeElement === 'undefined') { // Check browser doesn't do it anyway
  $('*').live('focus', function () { // Attach to all focus events using .live()
    document.activeElement = this; // Set activeElement to the element that has been focussed
  });
}

5

JQuery kullanıyorsanız, bir öğenin etkin olup olmadığını öğrenmek için bunu kullanabilirsiniz:

$("input#id").is(":active");


3

Sonunda bulduğum çözümü vermek için buraya koyuyorum.

Document.activeInputArea adlı bir özellik oluşturdum ve jQuery'nin HotKeys eklentisini ok tuşları, sekme ve enter için klavye olaylarını yakalamak için kullandım ve giriş öğelerini tıklatmak için bir olay işleyici oluşturdum.

Sonra her odak değiştiğinde activeInputArea ayarladım, böylece nerede olduğumu bulmak için bu özelliği kullanabilirsiniz.

Ancak bunu düzeltmek kolaydır, çünkü sistemde bir hata varsa ve odak düşündüğünüz yerde değilse, doğru odağı geri yüklemek çok zordur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.