关于javascript:我如何找出哪个DOM元素具有焦点?

How do I find out which DOM element has the focus?

我想在javascript中找出当前哪个元素具有焦点。我一直在查看DOM,但还没有找到我需要的东西。有没有办法,怎么做?

我找这个的原因是:

我试图让箭头和enter这样的键在输入元素表中导航。选项卡现在可以工作,但是输入,默认情况下箭头不会显示。我已经设置了关键处理部分,但现在我需要弄清楚如何在事件处理函数中转移焦点。


使用document.activeElement,所有主要浏览器都支持。

以前,如果您试图找出哪个表单字段具有焦点,则无法找到。要在旧浏览器中模拟检测,请向所有字段添加"焦点"事件处理程序,并在变量中记录最后一个焦点字段。添加一个"blur"处理程序,在最后一个焦点字段的blur事件上清除变量。

相关链接:

  • 活动浏览器兼容性
  • jquery document.activeelement的替代项


正如JW所说,您找不到当前关注的元素,至少以一种独立于浏览器的方式。但是如果你的应用是IE(有些是…),你可以通过以下方式找到它:

1
document.activeElement

编辑:看起来IE并没有出错,这是HTML5草案的一部分,至少在最新版本的Chrome、Safari和Firefox中得到了支持。


如果您可以使用jquery,它现在支持:focus,只要确保您使用的是1.6+版本。

此语句将使您获得当前关注的元素。

1
$(":focus")

发件人:如何使用jquery选择关注它的元素


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.bodydocument.documentElement进行检查的代码中,这是因为有些浏览器在没有焦点时返回其中一个或null

它不能解释是否(或可能是否具有tabIndex属性,因此实际上可以集中。如果你在写一个图书馆或者其他什么东西,并且希望它是健壮的,你应该以某种方式处理它。

这里有一个(重引号)"一行"版本的获得重点元素,这在概念上更复杂,因为你必须知道短路,而且你知道,它显然不适合一行,假设你希望它是可读的。我不推荐这个。但如果你是1337哈克斯,IDK…就在那里。如果您不介意在某些情况下使用false,也可以删除|| null部分。(如果document.activeElementnull,你仍然可以得到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' )


我喜欢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);


我在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

我希望有所帮助。