我想在JavaScript中找出当前具有焦点的元素。我已经查看了DOM,但仍未找到所需内容。是否可以实现这一点,如何实现?
我寻找这个功能的原因是:
我试图让像箭头和enter
这样的按键导航到一个输入元素的表格中。 Tab键现在可以工作,但似乎默认情况下enter键和箭头键无法操作。我已经设置好了按键处理部分,但现在需要在事件处理函数中弄清如何移动焦点。
我想在JavaScript中找出当前具有焦点的元素。我已经查看了DOM,但仍未找到所需内容。是否可以实现这一点,如何实现?
我寻找这个功能的原因是:
我试图让像箭头和enter
这样的按键导航到一个输入元素的表格中。 Tab键现在可以工作,但似乎默认情况下enter键和箭头键无法操作。我已经设置好了按键处理部分,但现在需要在事件处理函数中弄清如何移动焦点。
使用 document.activeElement
,它在所有主要浏览器中都受支持。
以前,在尝试找出哪个表单字段拥有焦点时,你是无法获取的。为了在旧版浏览器中模拟检测,需要为所有字段添加“focus”事件处理程序,并将最后一个聚焦的字段记录在变量中。为最后一个聚焦的字段添加“blur”处理程序以在模糊事件发生时清除变量。
如果需要移除 activeElement
,可以使用 blur;document.activeElement.blur()
。它会将 activeElement
更改为 body
。
相关链接:
activeElement
实际上并不返回聚焦的元素。任何元素都可以获得焦点。如果一个文档有 4 个滚动区域 ('scrolldivs'),其中 0 或 1 个区域可以通过箭头键进行滚动。如果您单击其中一个,那么该区域就会获得焦点。如果您在所有区域外单击,则 body 元素获得焦点。如何找出哪个滚动区域具有焦点?http://jsfiddle.net/rudiedirkx/bC5ke/show/ (检查控制台) - Rudiediv
的主要浏览器是 Firefox 17,并且只能通过“tab”键聚焦到它。所有主要浏览器返回 document.activeElement
的元素类型都限制在与输入相关的元素上。如果没有这样的元素具有焦点,所有主要浏览器都会返回 body
元素 - 唯独 IE 9 返回 html
元素。 - mklement0document.activeElement
时,应该用 try catch
包装起来,因为在某些情况下它可能会抛出异常(不仅限于 IE9)。请参阅 http://bugs.jquery.com/ticket/13393 和 http://bugs.jqueryui.com/ticket/8443。 - robocat正如JW所说,你无法以浏览器无关的方式找到当前聚焦的元素。但如果你的应用程序仅限于IE(有些应用是这样的...),你可以按照以下方式找到它:
document.activeElement
看起来IE并没有彻底错了,这是HTML5草案的一部分,最新版本的Chrome、Safari和Firefox至少支持这一点。
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
- Harry Pehkonendocument.querySelector( ':focus' )
很好用,而且被 jQuery 使用。 - V.Volkovdocument.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");
需要注意的是这两种方法之间的性能差异。使用选择器查询文档将始终比访问activeElement
属性慢得多。请参见此jsperf.com test。
单独使用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.body
和document.documentElement
,是因为一些浏览器在没有聚焦时返回其中之一或null
。
这并没有考虑<body>
(或者<html>
)有一个tabIndex
属性,因此实际上可以被聚焦。如果你正在编写一个库或其他东西,并希望它具有鲁棒性,那么你应该想办法处理这个问题。
下面是一个(笨重的引号)“单行”版的获取聚焦元素的版本,它在概念上更加复杂,因为你需要知道短路规则,而且你肯定无法将其放在一行上以使其可读。
我不会推荐使用这个版本。但是如果你是一个1337 hax0r,我也不知道...... 它在那里。
如果您不介意在某些情况下获得false
,则可以删除|| null
部分。(如果document.activeElement
是null
,你仍然可以获得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;
});
您可以通过使用非事件方式来修复初始状态假设,但那样的话您最好直接使用它。
document.activeElement
可能会在没有焦点元素时默认为 <body>
元素。此外,如果某个元素被聚焦并且浏览器窗口失去焦点,则 activeElement
将继续保持该元素。
如果这两种行为都不符合要求,请考虑使用基于 CSS 的方法:document.querySelector(':focus')
。
querySelector
:https://dev59.com/K3RB5IYBdhLWcg3w1Kle#40873560 - 1j01我发现以下代码片段在确定当前拥有焦点的元素时非常有用。将以下内容复制到您浏览器的控制台中,每秒钟它都会打印出当前拥有焦点的元素的详细信息。
setInterval(function() { console.log(document.querySelector(":focus")); }, 1000);
随意修改console.log
,将其日志记录为其他内容,以帮助您定位确切的元素,如果整个元素的打印不能帮助您确定该元素,请这样做。
我喜欢Joel S使用的方法,但我也喜欢document.activeElement
的简单性。我使用了jQuery并将两者结合起来。不支持document.activeElement
的旧版浏览器将使用jQuery.data()
存储'hasFocus'的值。较新的浏览器将使用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);
$("*:focus")
替换? - PylinuxFocusTracker = {
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);
如果给定元素调用了startFocusTracking()
,那么您可以使用el.hasFocus()
来检查元素是否具有焦点。
:focus
伪类。如果在JQuery文档中查找,可以在“选择器”下检查,其中会指向W3C CSS docs。我已经在Chrome、FF和IE 7+上进行了测试。请注意,在IE中要使其工作,必须在html页面上存在<!DOCTYPE...
。以下是一个示例,假设您已经给具有焦点的元素分配了一个id:$(":focus").each(function() {
alert($(this).attr("id") + " has focus!");
});
this.id
而不是$(this).attr('id')
,或者至少(当你已经有了jQuery对象时)使用$(this)[0].id
。在这个级别上,原生JavaScript更快、更高效。在这种情况下可能不会注意到,但在整个系统范围内,你会注意到差异。 - Martijn
find-focused-element
包:https://www.npmjs.com/package/find-focused-element - Maxim Zhukovdocument.activeElement
的使用示例:https://dev59.com/_G025IYBdhLWcg3wqn0N#64176168 - AndrewnextFocus(element, keyboardEvent) // => 返回应接收焦点的元素
- bas080