JavaScriptで、どの要素が現在フォーカスされているのかを調べたいと思います。私はDOMを調べていて、まだ必要なものを見つけていません。これを行う方法はありますか?
私がこれを探していた理由:
私は矢印やenter
のようなキーを入力要素のテーブルをナビゲートしようとしています。タブは今動作しますが、入力し、矢印はデフォルトではないようです。キー処理部分を設定しましたが、今度はイベント処理関数でフォーカスを移動する方法を理解する必要があります。
document.activeElement
を使用してください。これはすべての主要ブラウザでサポートされています。
以前は、どのフォームフィールドにフォーカスがあるのかを調べようとしていたのではありませんでした。古いブラウザで検出をエミュレートするには、すべてのフィールドに "focus"イベントハンドラを追加し、最後にフォーカスしたフィールドを変数に記録します。最後にフォーカスされたフィールドのブラーイベントの際に変数をクリアするための「ブラー」ハンドラを追加します。
関連リンク:
JWが言ったように、少なくともブラウザに依存しない方法では、現在注目している要素を見つけることはできません。しかし、あなたのアプリがIEのみの場合(いくつかは...)、次のようにして見つけることができます。
document.activeElement
編集:IEには結局問題がないわけではなく、これはHTML5ドラフトの一部であり、少なくともChrome、Safari、Firefoxの最新バージョンでサポートされているようです。
あなたがjQueryを使うことができるならば、それは今サポートします:フォーカス、ちょうどあなたがバージョン1.6+を使っていることを確認してください。
このステートメントはあなたに現在焦点を当てている要素を取得します。
$(":focus")
document.activeElement
は現在 HTML 5ワーキングドラフト の仕様の一部ですが、一部のメジャー/モバイル/古いブラウザではまだサポートされていない可能性があります。 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 test を参照してください。
文書がフォーカスされていない場合、document.activeElement
はそれ自体で要素を返すことができます(したがって、ドキュメント内の何もフォーカスされていません!)
あなたはmayその振る舞いを望んでいるか、それともmayは重要ではありません(例えばkeydown
イベント内)、しかし何かを知る必要があるなら実際にフォーカスされている場合は、さらに document.hasFocus()
を確認できます。
以下は、ある場合はフォーカスされた要素を、そうでなければnull
を提供します。
var focused_element = null;
if (
document.hasFocus() &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement
) {
focused_element = document.activeElement;
}
specific要素にフォーカスがあるかどうかを確認するには、より簡単です:
var input_focused = document.activeElement === input && document.hasFocus();
anythingがフォーカスされているかどうかを確認するには、さらに複雑です。
var anything_is_focused = (
document.hasFocus() &&
document.activeElement !== null &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement
);
堅牢性注:document.body
およびdocument.documentElement
に対するチェックを行うコードでは、一部のブラウザーがこれらのいずれかを返すためです。またはnull
は何もフォーカスされていない場合。
<body>
(または<html>
)にtabIndex
属性があり、したがってが実際にフォーカスできるかどうかは考慮されません。ライブラリなどを作成していて、堅牢にしたい場合は、おそらくそれを何らかの方法で処理する必要があります。
これは(heavyairquotes)フォーカスされた要素を取得する「ワンライナー」バージョンです。これは概念的にもっと複雑です -circuiting、そしてあなたがそれを読みやすくしたいのであれば、それは明らかに1行に収まりません。
これはお勧めしません。しかし、もしあなたが1337 hax0rなら、idk ...そこにあります。
場合によってはfalse
を取得しても構わないのであれば、|| null
部分を削除することもできます。 (document.activeElement
がnull
の場合、null
を取得できます):
var focused_element = (
document.hasFocus() &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement &&
document.activeElement
) || null;
特定の要素がフォーカスされているかどうかを確認するには、代わりにcouldイベントを使用しますが、この方法ではセットアップ(および潜在的にティアダウン)が必要であり、重要なことに、は初期状態を想定します:
var input_focused = false;
input.addEventListener("focus", function() {
input_focused = true;
});
input.addEventListener("blur", function() {
input_focused = false;
});
イベントなしの方法を使用して初期状態の仮定を修正できますが、代わりにそれを使用することもできます。
フォーカス可能な要素にフォーカスがない場合、document.activeElement
はデフォルトで<body>
要素になります。さらに、要素がフォーカスされていてブラウザウィンドウがぼやけている場合、activeElement
はフォーカスされた要素を保持し続けます。
これら2つの動作のどちらかが望ましくない場合は、CSSベースのアプローチdocument.querySelector( ':focus' )
を検討してください。
私はJoel Sが使っていたアプローチが好きでしたが、document.activeElement
の単純さも好きです。私はjQueryを使い、両者を組み合わせました。 document.activeElement
をサポートしない古いブラウザは、 'hasFocus'の値を格納するために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);
私が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()
でフォーカスされているかどうかをチェックできます。
JQueryは現在の:focus
疑似クラスをサポートしています。 JQueryのドキュメントで探しているのなら、 "="の下の "Selectors"で W3C CSSドキュメント をチェックしてください。 Chrome、FF、IE 7+でテストしました。 IEで動作するには、<!DOCTYPE...
がhtmlページに存在している必要があります。これは、フォーカスがある要素にIDを割り当てたと仮定した例です。
$(":focus").each(function() {
alert($(this).attr("id") + " has focus!");
});
Element
のインスタンスであるオブジェクトを取得したい場合はdocument.activeElement
を使用する必要がありますが、Text
のインスタンスであるオブジェクトを取得したい場合はdocument.getSelection().focusNode
を使用する必要があります。
助けていただければ幸いです。
Document.activeElementの使用には潜在的な問題があります。検討してください:
<div contentEditable="true">
<div>Some text</div>
<div>Some text</div>
<div>Some text</div>
</div>
ユーザーがinner-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;
}
}
他の答えを読んで、自分で試してみると、ほとんどのブラウザで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
});
}
JQueryを使用している場合は、これを使用して要素がアクティブかどうかを調べることができます。
$("input#id").is(":active");
Dojoでは、dijit.getFocus()を使用できます。
現在どの要素にフォーカスがあるのかを判断する際には、次のスニペットが役立つことがわかりました。以下をブラウザのコンソールにコピーすると、毎秒フォーカスが当たっている現在の要素の詳細が表示されます。
setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);
要素全体を印刷しても要素を特定できない場合は、console.log
を修正して別のログアウトして正確な要素を特定できるようにしてください。
私が最終的に思いついた解決策を与えるためにここにこれを置くだけです。
Document.activeInputAreaというプロパティを作成し、jQueryのHotKeysアドオンを使用して矢印キー、Tabキー、Enterキーのキーボードイベントをトラップし、入力要素をクリックするためのイベントハンドラを作成しました。
その後、フォーカスが変わるたびにactiveInputAreaを調整したので、そのプロパティを使用して自分がどこにいるのかを確認できます。
ただし、システムにバグがあり、意図した場所にフォーカスがない場合は、正しいフォーカスを復元するのが非常に困難です。