どのDOM要素にフォーカスがあるかを知るにはどうすればよいですか?


1309

JavaScriptで、現在どの要素がフォーカスされているかを確認したいと思います。私はDOMを調べてきましたが、必要なものがまだ見つかりません。これを行う方法はありますか?

私がこれを探していた理由:

矢印のようなキーを作成しenter、入力要素のテーブルをナビゲートしようとしています。タブは動作しますが、Enterキーを押します。デフォルトでは、矢印は表示されません。キー処理パーツをセットアップしましたが、イベント処理関数でフォーカスを移動する方法を理解する必要があります。


2
これは、フォーカスがある要素をconsole.logに記録するブックマークレットです:github.com/lingtalfi/where-is-focus-bookmarklet
ling

find-focused-elementパッケージを使用できます:npmjs.com/package/find-focused-element
Maxim Zhukov

回答:


1533

を使用するとdocument.activeElement、すべての主要なブラウザでサポートされます。

以前は、どのフォームフィールドがフォーカスされているかを調べようとしても、できませんでした。古いブラウザー内で検出をエミュレートするには、すべてのフィールドに「フォーカス」イベントハンドラーを追加し、最後にフォーカスされたフィールドを変数に記録します。「blur」ハンドラを追加して、最後にフォーカスされたフィールドのblurイベントで変数をクリアします。

削除する必要があるactiveElement場合は、ぼかしを使用できます。document.activeElement.blur()。に変更さactiveElementbodyます。

関連リンク:


53
IEについては不明ですが、FFとSafariはどちらもBODY要素を返します。
JW。

10
activeElement実際にはフォーカスされた要素を返しません。どの要素でもフォーカスを持つことができます。ドキュメントに4つの 'scrolldiv'がある場合、それらのdivのうち0または1つを矢印キーでスクロールできます。いずれかをクリックすると、そのdivがフォーカスされます。すべての外側をクリックすると、ボディがフォーカスされます。どのscrolldivがフォーカスされているかをどのようにして見つけますか?jsfiddle.net/rudiedirkx/bC5ke/show(コンソールを確認)
Rudie

18
@Rudie、@Stewartは:私は、より精巧な遊び場を作成するためにあなたのフィドル上に構築されました:jsfiddle.net/mklement/72rTF。(2012年後半の時点で)実際にそのようなものに焦点を当てることができる唯一の主要なブラウザーdivはFirefox 17であり、それにタブで移動するだけです。すべての主要なブラウザが返す要素のタイプはdocument.activeElement入力関連の要素に制限されています。そのような要素にフォーカスがない場合、すべての主要ブラウザはbody要素を返します-IE 9はhtml要素を返します。
mklement0

10
それが役立つかどうかはわかりませんが、divのような要素に属性tabindex = "0"を含めることでキーボードフォーカスを受け取ることができます
Marco Luglio

4
一部の状況では例外をスローする可能性があるため(IE9 AFAIKだけでなく)document.activeElement、へのアクセスはすべてラップする必要がありますtry catchbugs.jquery.com/ticket/13393およびbugs.jqueryui.com/ticket/8443を
robocat

127

JWが言ったように、少なくともブラウザに依存しない方法では、現在フォーカスされている要素を見つけることができません。しかし、アプリがIEのみの場合(一部は...)、次の方法で見つけることができます。

document.activeElement

編集:結局のところ、IEに問題はなかったようです。これはHTML5ドラフトの一部であり、少なくともChrome、Safari、Firefoxの最新バージョンでサポートされているようです。


5
FF3も。これは実際には、「フォーカス管理」に関するHTML5仕様の一部です。
クレセントフレッシュ

2
現在のバージョンのChromeとOpera(9.62)で動作します。OS X上のSafari 3.2.3では機能しませんが、昨日リリースされたSafari 4では機能します:)
gregers

まだ同じクロム19用:S
Sebas

1
キーボードを使用して要素にタブで移動する場合にのみ、クロム(20)/サファリ(5.1.3)で機能します。これをクリックすると、jquery:focusセレクターもdocument.activeElementも、クリックしたものを返すことに成功しません(それぞれ未定義の要素とドキュメントの本文の要素を返します)。PSこのスレッドが2年前であるとは信じられません。スキップリンクが機能しないものとともに、webkitには依然として回帰の問題がありますが、実験的なcss3を追加することで多くの作業が行われています。私が家族や友人にFirefoxを推奨することに戻るかもしれないと思います。
夜明け

^^ document.activeElementは、テキスト領域またはその他の入力をクリックしてフォーカスするときに問題ありません。リンクの場合、(ページ内または明らかにそれ以外の場合)クリックしてもフォーカスされません。
markyzm

84

jQueryを使用できる場合は、:focusがサポートされるようになりました。バージョン1.6以降を使用していることを確認してください。

このステートメントは、現在フォーカスされている要素を取得します。

$(":focus")

From:jQueryでフォーカスされている要素を選択する方法


4
これは良いですが、jQueryはそれをどのように行うのですか?document.activeElement?私はこれを見つけました: return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
ハリー・ペコネン2017年

46

document.activeElementは現在HTML5ワーキングドラフト仕様の一部ですが、一部の非メジャー/モバイル/古いブラウザーではまだサポートされていない可能性があります。フォールバックできますquerySelector(サポートされている場合)。要素がフォーカスされていない場合は、ブラウザウィンドウにフォーカスがない場合でもdocument.activeElement返されることにも言及する価値document.bodyがあります。

次のコードはこの問題を回避しquerySelector、もう少し良いサポートを提供することにフォールバックします。

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

さらに注目すべきは、これら2つの方法のパフォーマンスの違いです。セレクターを使用したドキュメントのクエリは、activeElementプロパティへのアクセスよりも常に遅くなります。このjsperf.comテストを参照してください。


21

それ自体でdocument.activeElement、ドキュメントがフォーカスされていない(したがって、ドキュメント内の何もフォーカスされていない)場合でも要素を返すことができます。

あなたその振る舞いを望むかもしれませんし、それ問題でないかもしれません(例えば、keydownイベント内)が、何かが実際にフォーカスされていることを知る必要があるなら、さらにチェックすることができますdocument.hasFocus()

次の例では、フォーカスされた要素がある場合はそれを提供しますnull

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

特定の要素にフォーカスがあるかどうかを確認するには、より簡単です。

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

何かに焦点が当てられているかどうかを確認するために、再び複雑になります。

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

堅牢性注document.bodyandをチェックするコードでdocument.documentElementは、一部のブラウザーがこれらの1つを返すかnull、何もフォーカスされていない場合にこれが発生します。

<body>(または多分<html>)にtabIndex属性があり、したがって実際にフォーカスできるかどうかは考慮されません。ライブラリなどを作成していて、それを堅牢にしたい場合は、おそらく何らかの方法で処理する必要があります。


これは、(重いエアクォート)フォーカスされた要素を取得する「ワンライナー」バージョンです。これは、短絡について知っている必要があるため、概念的にはより複雑です。読みやすくしたい。
これはお勧めしません。しかし、1337 hax0r、idkの場合は、そこにあります。場合によっては
|| nullパーツを取り除いてもかまいませんfalse。(あなたはまだ得ることができるnull場合document.activeElementですnull):

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

特定の要素がフォーカスされているかどうかを確認するために、代わりにイベントを使用することもできますが、この方法ではセットアップ(および場合によっては破棄)が必要であり、重要なことに、初期状態を想定しています

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

イベントなしの方法を使用して初期状態の仮定を修正できますが、代わりにそれを使用することもできます。


15

document.activeElement<body>フォーカス可能な要素にフォーカスがない場合、デフォルトで要素になります。さらに、要素がフォーカスされていて、ブラウザウィンドウがぼやけている場合、activeElementはフォーカスされた要素を保持し続けます。

これら2つの動作のいずれかが望ましくない場合は、CSSベースのアプローチを検討してくださいdocument.querySelector( ':focus' )


クール、そうです、私の場合、あなたのアプローチは絶対的に理にかなっています。フォーカス可能な要素を 'tabindex = "-1"'で設定できます。それらのどれにもフォーカスがない場合(たとえば、気にしないいくつかのテキストまたは画像)、document.querySelector( ':focus')が返されますヌル。
Manfred

使用を避けるために私の答えを参照してくださいquerySelectorstackoverflow.com/a/40873560/2624876
1j01

10

Joel Sのアプローチが好きでしたが、の単純さも気に入っていdocument.activeElementます。私はjQueryを使用して2つを組み合わせました。サポートしていない古いブラウザは、「hasFocus」の値を格納document.activeElementするために使用jQuery.data()します。新しいブラウザはを使用しますdocument.activeElement。私はそれdocument.activeElementがより良いパフォーマンスを持っていると思います。

(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
これを@William Dennissで置き換えることはでき$("*:focus")ますか?
Pylinux 2015

できたと思います。私はこれをずっと前に書きましたが、5年経った今、より良い解決策を再検討する理由がありませんでした。やってみて!私も同じようにするかもしれません。私のサイトではプラグインを減らしました!:)
Jason

10

Mootoolsでこれらの目的に使用した小さなヘルパー:

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);

要素が持つフォーカスがあるかどうかをチェックすることができます。この方法でel.hasFocus()提供するstartFocusTracking()特定の要素で呼び出されましたが。


7

jQueryは、現在のところ、:focus疑似クラスをサポートしています。JQueryのドキュメントで探している場合は、「セレクター」でW3C CSSドキュメントを参照できる場所を確認してください。私はChrome、FF、IE 7以降でテストしました。IEで動作<!DOCTYPE...するためには、htmlページに存在する必要があることに注意してください。フォーカスのある要素にIDを割り当てたと仮定した例を次に示します。

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

1
(常に?)のthis.id代わりに$(this).attr('id')、または少なくとも(すでにjQueryオブジェクトを持っている場合)を使用する必要があります$(this)[0].id。このレベルのネイティブJavascriptは、WAYより速く、より効率的です。この場合は目立たないかもしれませんが、システム全体で違いに気付くでしょう。
Martijn、2015

7

のインスタンスであるオブジェクトを取得するにはElement、を使用する必要document.activeElementがありますがText、のインスタンスであるオブジェクトを取得するには、を使用する必要がありますdocument.getSelection().focusNode

お役に立てば幸いです。


どのように良いですか?
1j01

ブラウザのインス​​ペクタを開き、ページの任意の場所をクリックして、これdocument.getSelection().focusNode.parentElementを過ぎてEnterをタップします。その後、過去document.activeElementと同じことを行います。;)
rplaurindo

このコメントボックスにフォーカスして、document.activeElement与え<textarea>に対しdocument.getSelection().focusNode与え<td>含まれている<textarea>(とdocument.getSelection().focusNode.parentElement与え<tr>含む<td>
1j01

すみません、すみません。私はそれをうまく説明しませんでした。あなたがのインスタンスであるオブジェクトを取得したい場合Elementは、使用する必要がありますdocument.activeElementが、あなたはのインスタンスであるオブジェクトを取得したい場合Textは、使用する必要がありますdocument.getSelection().focusNode。もう一度テストしてください。私が助けてくれたら幸いです。
rplaurindo 16

2
問題は、現在どの要素にフォーカスがあるかを尋ねることです。また、focusNodeテキストノードであるとは限りません。
1j01

6

document.activeElementの使用には潜在的な問題があります。検討してください:

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

ユーザーが内部divに焦点を合わせている場合、document.activeElementは引き続き外部divを参照します。document.activeElementを使用して、どの内部divにフォーカスがあるかを判断することはできません。

次の関数はこれを回避し、フォーカスされたノードを返します。

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

フォーカスされた要素を取得したい場合は、以下を使用します。

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

3
これは実際には問題ではありません。疑似クラスを目に見えるものに設定することで視覚的に確認できるように、document.activeElement内部<div>要素は実際にはフォーカスを受け取ることができません:focus(例:jsfiddle.net/4gasa1t2/1)。あなたが話していること<div>は、別の問題である選択またはキャレットが含まれている内部のsです。
Tim Down

6

次のスニペットは、現在どの要素にフォーカスがあるかを判断するときに役立ちます。以下をブラウザーのコンソールにコピーすると、フォーカスがある現在の要素の詳細が毎秒出力されます。

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

console.log要素全体を印刷しても要素を正確に特定できない場合は、を変更して、別の何かをログアウトして、正確な要素を特定できるようにしてください。


5

他の回答を読んで自分で試してみると、document.activeElementほとんどのブラウザで必要な要素が得られるようです。

jQueryを使用している場合にdocument.activeElementをサポートしていないブラウザーを使用している場合は、すべてのフォーカスイベントに次のような非常に単純なものを設定できるはずです(これらの基準を満たすブラウザーがないため、テストする必要はありません)。 ):

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を使用している場合は、これを使用して要素がアクティブかどうかを確認できます。

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


3

これをここに置くだけで、最終的に私が思いついた解決策が得られます。

document.activeInputAreaというプロパティを作成し、jQueryのHotKeysアドオンを使用して、矢印キー、タブ、Enterのキーボードイベントをトラップし、入力要素をクリックするためのイベントハンドラーを作成しました。

次に、フォーカスが変わるたびにactiveInputAreaを調整したので、そのプロパティを使用して自分がどこにいるかを確認できます。

ただし、システムにバグがあり、フォーカスが意図した場所にない場合、正しいフォーカスを復元するのは非常に難しいため、これを台無しにするのは簡単です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.