我想在javascript中找出当前哪个元素具有焦点。我一直在查看DOM,但还没有找到我需要的东西。有没有办法,怎么做?
我找这个的原因是:
我试图让箭头和enter这样的键在输入元素表中导航。选项卡现在可以工作,但是输入,默认情况下箭头不会显示。我已经设置了关键处理部分,但现在我需要弄清楚如何在事件处理函数中转移焦点。
- 这里有一个控制台的书签。用焦点记录元素:GITHUB.COM/LIGTALFI/WHE-IS-FooCu-BookMulk
使用document.activeElement,所有主要浏览器都支持。
以前,如果您试图找出哪个表单字段具有焦点,则无法找到。要在旧浏览器中模拟检测,请向所有字段添加"焦点"事件处理程序,并在变量中记录最后一个焦点字段。添加一个"blur"处理程序,在最后一个焦点字段的blur事件上清除变量。
相关链接:
- 活动浏览器兼容性
- jquery document.activeelement的替代项
- 如果没有聚焦元素,document.activeelement返回什么?我们能依赖它在支持它的浏览器之间保持一致吗?
- 对IE不确定,但是FF和Safari都返回body元素。
- 我们是否有权知道之前关注的是哪个要素?
- 不,你得自己跟踪。
- activeElement实际上不返回聚焦元素。任何元素都可以有焦点。如果一个文档有4个"滚动分隔符",则这些分隔符中的0或1可以通过箭头键滚动。如果单击其中一个,则该分区将被聚焦。如果你点击所有外部,身体就会集中。如何找出哪个ScrollDiv是焦点?jsfiddle.net/rudiderkx/bc5ke/show(检查控制台)
- @鲁迪,@stewart:I've build on your fiddle to create a more preciency playground:jsfiddle.net/mkelement/72rtf.你会发现,唯一能真正聚焦于这样一个div的主要浏览器(截至2012年底)是firefox 17,而且只需点击它。所有主要浏览器通过document.activeElement返回的元素类型都限制为与输入相关的元素。如果没有这样的元素具有焦点,那么所有的主要浏览器都会返回body元素,但ie 9除外,后者返回html元素。
- @jw:ie(从v9开始)返回html元素。Safari、Chrome、Firefox、Opera的当前版本(截至2012年底)均返回body元素。
- 在XHTML文档中,'activeElement' in document是chrome(26)中的false。不过,如果您想知道是否有任何输入元素被聚焦,那么document.querySelector(':focus')工作得很好。
- 不确定是否有帮助,但是您可以通过包含属性tabindex="0"使一个元素(如div)接收键盘焦点。
- 对document.activeElement的任何访问都应包装在try catch中,因为在某些情况下,它可能引发异常(不仅仅是ie9 afaik)。请参见bugs.jquery.com/ticket/13393和bugs.jqueryui.com/ticket/8443
- 我更新了@mkelement/rudie的jfiddle。正如FacildelemBrar所说,您可以使用tabindex访问它。见jsfiddle.net/72rtf/34
正如JW所说,您找不到当前关注的元素,至少以一种独立于浏览器的方式。但是如果你的应用是IE(有些是…),你可以通过以下方式找到它:
编辑:看起来IE并没有出错,这是HTML5草案的一部分,至少在最新版本的Chrome、Safari和Firefox中得到了支持。
- FF3也一样。这实际上是HTML5关于"焦点管理"的规范的一部分。
- 它适用于当前版本的Chrome和Opera(9.62)。不适用于OS X上的Safari 3.2.3,但适用于昨天发布的Safari 4:)
- 是的,它在最新的Chrome(稳定版本)中工作得很好。
- 现在不能在Chrome(15.0…)中工作,它会返回Body。
- 铬19:S的情况仍然一样
- 它只在Chrome(20)/Safari(5.1.3)中工作,当您使用键盘在元素上制表时。如果单击它,jquery:focus选择器和document.activeelement都不会成功返回您单击的内容(分别返回undefined和document body元素)。PS我不敢相信这个线程已经2年了,WebKit上仍然存在回归问题,还有一个跳过链接不起作用的问题,但是在添加实验CSS3方面做了很多工作。我想我可以回去向我的家人和朋友推荐火狐。
- ^^单击以聚焦于文本区域或其他输入时,document.activeelement可以。如果它是一个链接,则在单击时(在页面中或明显的其他位置)不会聚焦。
如果您可以使用jquery,它现在支持:focus,只要确保您使用的是1.6+版本。
此语句将使您获得当前关注的元素。
发件人:如何使用jquery选择关注它的元素
- 这很好,但是jquery是如何做到的呢?文档.活动?我发现这个:return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);。
document.activeElement现在是HTML5工作草案规范的一部分,但在一些非主要/移动/旧版本的浏览器中可能还不支持它。您可以返回到querySelector(如果支持的话)。值得一提的是,如果没有聚焦元素,即使浏览器窗口没有聚焦,document.activeElement也会返回document.body。
下面的代码将解决这个问题,并返回到querySelector,提供更好的支持。
1 2 3 4 5
| var focused = document.activeElement;
if (!focused || focused == document.body)
focused = null;
else if (document.querySelector)
focused = document.querySelector(":focus"); |
另外需要注意的是这两种方法之间的性能差异。使用选择器查询文档总是比访问activeElement属性慢得多。请参阅jspef.com测试。
本身,如果文档没有焦点,document.activeElement仍然可以返回元素(因此文档中没有焦点!)
你可能想要这种行为,或者它可能无关紧要(例如在keydown事件中),但是如果你需要知道某件事情实际上是集中的,你可以另外检查document.hasFocus()。
如果有焦点元素,下面将为您提供焦点元素,否则将提供null。
1 2 3 4 5 6 7 8
| var focused_element = null;
if (
document.hasFocus() &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement
) {
focused_element = document.activeElement;
} |
要检查特定元素是否具有焦点,更简单的方法是:
1
| var input_focused = document.activeElement === input && document.hasFocus(); |
为了检查是否有什么东西是集中的,它又变得更复杂了:
1 2 3 4 5 6
| var anything_is_focused = (
document.hasFocus() &&
document.activeElement !== null &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement
); |
稳健性说明:在对document.body和document.documentElement进行检查的代码中,这是因为有些浏览器在没有焦点时返回其中一个或null。
它不能解释是否(或可能是否具有tabIndex属性,因此实际上可以集中。如果你在写一个图书馆或者其他什么东西,并且希望它是健壮的,你应该以某种方式处理它。
这里有一个(重引号)"一行"版本的获得重点元素,这在概念上更复杂,因为你必须知道短路,而且你知道,它显然不适合一行,假设你希望它是可读的。我不推荐这个。但如果你是1337哈克斯,IDK…就在那里。如果您不介意在某些情况下使用false,也可以删除|| null部分。(如果document.activeElement是null,你仍然可以得到null:
1 2 3 4 5 6
| var focused_element = (
document.hasFocus() &&
document.activeElement !== document.body &&
document.activeElement !== document.documentElement &&
document.activeElement
) || null; |
为了检查特定元素是否集中,您也可以使用事件,但这种方式需要设置(并且可能需要拆卸),而且重要的是,假定初始状态:
1 2 3 4 5 6 7
| var input_focused = false;
input.addEventListener("focus", function() {
input_focused = true;
});
input.addEventListener("blur", function() {
input_focused = false;
}); |
您可以使用非事件的方法来修复初始状态假设,但是您也可以使用它来代替。
如果焦点中没有可聚焦元素,则document.activeElement可以默认为元素。此外,如果某个元素被聚焦,并且浏览器窗口模糊,那么activeElement将继续保持聚焦元素。
如果这两种行为中的任何一种都不可取,那么考虑一种基于CSS的方法:document.querySelector( ':focus' )。
- 酷,对我来说,你的方法绝对有道理。我可以使用"tabindex="-1"设置可聚焦元素,如果它们都没有焦点(例如,一些我不关心的文本或图片)。queryselector(":focus")返回空值。
- 请参阅我的答案以避免使用querySelector:stackoverflow.com/a/40873560/2624876
我喜欢Joel S使用的方法,但我也喜欢document.activeElement的简单性。我使用jquery并将两者结合起来。不支持document.activeElement的旧浏览器将使用jQuery.data()来存储"hasfocus"的值。较新的浏览器将使用document.activeElement。我认为document.activeElement会有更好的性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| (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); |
- 可以用@william denniss的$("*:focus")来代替吗?
- 我想可以。我很久以前就写了这篇文章,5年后我再也没有理由重新考虑一个更好的解决方案。试试看!我也可以这么做。我们网站上的插件少了!:)
我在moooltools中使用过的一个小助手:
1 2 3 4 5 6 7 8 9 10 11 12 13
| 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()。
如果你想要得到一个Element实例的对象,你必须使用document.activeElement,但是如果你想要得到一个Text实例的对象,你必须使用document.getSelection().focusNode。
我希望有所帮助。
- 哪方面更好?
- 打开浏览器的Inspector,单击页面的任何位置,经过此document.getSelection().focusNode.parentElement,然后点击Enter。在那之后,经过以东十一〔二〕并做同样的事。;)
- 以这个评论框为中心,document.activeElement给出了,而document.getSelection().focusNode给出了
,其中包含(document.getSelection().focusNode.parentElement给出了
,其中包含
。
- 对不起,我道歉。我解释得不好。如果你想要得到一个Element实例的对象,你必须使用document.activeElement,但是如果你想要得到一个Text实例的对象,你必须使用document.getSelection().focusNode。请再测试一下。希望我能帮忙。
- 问题是问当前哪个元素具有焦点。而且focusNode也不能保证是文本节点。
- 是的,但是activeElement永远不会返回Text对象。例如,document.getSelection().focusNode保证Node的一个实例,点击一个元素后,该实例可以是Text或Element。这不是一个更好的问题,而是更合适的问题。
- 但这个问题需要一个元素,即Element。回答一个问题(在我看来)可以提到一个类似的情况,在这种情况下,你需要一个不同的解决方案,但"如果你想得到一个文本节点"并不是很有描述性。例如,你用这个做什么?
- 是的,问题是关于一个元素。我利用它,把信息添加到另一个案例中。重要的是,有些人会混淆,认为文本节点是一个元素,而实际上,元素是封装文本的元素。是Element和Text的Node实例,但Text不是Element实例。所以…我用来获取在HTML上选定的对象,然后在其上显示工具提示。
- 好吧,是的,那绝对是另一种情况。选择不是焦点。
- 事实并非如此。但可以是文本上的单击事件大小写,而不是所选内容。因此,getSelection方法返回的对象存在focusNode属性。
- 当您需要为输入的内容设置不同的操作时,它非常有用。虽然这不是关于当focusout触发时获取当前元素,但没有更好的方法。当焦点离开时,没有使用案例来获取元素。如果你需要的话,最好用鼠标。
jquery不支持当前的:focus伪类。如果您在jquery文档中查找它,请在"选择器"下选中它指向W3C CSS文档的位置。我用Chrome、FF和IE 7+测试过。请注意,要使其在IE中工作,HTML页面上必须存在。下面是一个示例,假设您为具有焦点的元素分配了一个ID:
1 2 3
| $(":focus").each(function() {
alert($(this).attr("id") +" has focus!");
}); |
- 你应该(总是?)使用this.id而不是$(this).attr('id'),或者至少(当您准备好jquery对象时)使用$(this)[0].id。这一级别的原生JavaScript速度更快、效率更高。在这种情况下可能不会被注意到,但在整个系统范围内,您会注意到一个区别。
使用document.activeelement可能存在问题。考虑:
1 2 3
| Some text
Some text
Some text |
如果用户将焦点放在一个内部分区上,那么document.activeelement仍然引用外部分区。您不能使用document.activeelement来确定哪个内部分区具有焦点。 以下函数将绕过此问题,并返回焦点节点:
1 2 3
| function active_node(){
return window.getSelection().anchorNode;
} |
如果您希望获得焦点元素,请使用:
1 2 3 4 5 6 7 8
| function active_element(){
var anchor = window.getSelection().anchorNode;
if(anchor.nodeType == 3){
return anchor.parentNode;
}else if(anchor.nodeType == 1){
return anchor;
}
} |
- 这不是document.activeElement的真正问题:内部元素实际上无法接收焦点,正如您通过将:focus伪类设置为可见的内容(例如:jsfiddle.net/4gasa1t2/1)可以看到的那样。你要说的是,哪个内部的中包含选择符或插入符号,这是一个单独的问题。
如果使用jquery,可以使用它来确定元素是否处于活动状态:
1
| $("input#id").is(":active"); |
阅读其他答案,并尝试自己,似乎document.activeElement将为您提供大多数浏览器所需的元素。 如果您的浏览器不支持document.activeelement如果您周围有jquery,您应该能够在所有焦点事件中使用类似的非常简单的内容填充它(未测试,因为我没有满足这些条件的浏览器):
1 2 3 4 5
| 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
});
} |
使用Dojo,您可以使用dijit.getfocus()。
我发现以下代码片段在尝试确定当前哪个元素具有焦点时很有用。将以下内容复制到浏览器的控制台中,它将每秒打印出具有焦点的当前元素的详细信息。
1
| setInterval(function() { console.log(document.querySelector(":focus")); }, 1000); |
如果打印出整个元素不能帮助您精确定位元素,请随意修改console.log以注销不同的内容以帮助您精确定位元素。
把这个放在这里给出我最终想出的解决方案。 我创建了一个名为document.activeinputArea的属性,并使用jquery的热键加载项为箭头键、制表符和回车键捕获键盘事件,我创建了一个用于单击输入元素的事件处理程序。 然后,每次焦点改变时,我都会调整ActiveInputArea,这样我就可以使用该属性来确定我在哪里。 不过,很容易把这个问题搞砸,因为如果系统中有一个bug,而焦点不在您认为的位置,那么很难恢复正确的焦点。
| |