如何找出哪个DOM元素具有焦点?

问题描述 投票:1172回答:16

我想在JavaScript中找出目前关注哪个元素。我一直在浏览DOM,但还没找到我需要的东西。有没有办法做到这一点,以及如何?

我之所以在寻找这个:

我正在尝试使用像箭头和enter这样的键来导航输入元素表。选项卡现在可以使用,但是输入,并且默认情况下不显示箭头。我已经设置了密钥处理部分,但现在我需要弄清楚如何在事件处理函数中移动焦点。

javascript dom
16个回答
1394
投票

使用document.activeElement,它在所有主流浏览器中都受支持。

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

相关链接:


7
投票

如果你想获得一个Element实例的对象,你必须使用document.activeElement,但如果你想获得一个Text实例的对象,你必须使用document.getSelection().focusNode

我希望有所帮助。


6
投票

使用document.activeElement可能存在问题。考虑:

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

如果用户关注内部d​​iv,则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;
  }
}

5
投票

阅读其他答案,并尝试自己,似乎document.activeElement将为您提供大多数浏览器所需的元素。

如果你有一个不支持document.activeElement的浏览器,如果你有jQuery,你应该可以在所有焦点事件上用这样的非常简单的东西填充它(未经测试,因为我没有满足这些标准的浏览器) ):

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

4
投票

使用dojo,您可以使用dijit.getFocus()


4
投票

我发现以下代码段在尝试确定哪个元素当前具有焦点时非常有用。将以下内容复制到浏览器的控制台中,每秒都会打印出具有焦点的当前元素的详细信息。

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

如果打印出整个元素无法帮助您精确定位元素,请随意修改console.log以注销不同的内容以帮助您精确定位元素。


3
投票

只是把它放在这里给出解决方案我最终想出来了。

我创建了一个名为document.activeInputArea的属性,并使用jQuery的HotKeys插件来捕获箭头键,tab和enter的键盘事件,并创建了一个用于单击输入元素的事件处理程序。

然后我每次焦点改变时都调整了activeInputArea,所以我可以使用该属性来找出我的位置。

虽然很容易搞砸了,但是如果你的系统中有一个bug并且焦点不在你想象的地方,那么很难恢复正确的焦点。


114
投票

正如JW所说,至少在与浏览器无关的方式中,你无法找到当前的焦点元素。但如果你的应用只是IE浏览器(有些是......),你可以通过以下方式找到它:

document.activeElement

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


78
投票

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

此语句将为您提供当前关注的元素。

$(":focus")

来自:How to select an element that has focus on it with jQuery


41
投票

document.activeElement现在是part of the HTML5 working draft规范,但在某些非主要/移动/旧版浏览器中可能尚未支持。您可以回退到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


17
投票

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

它没有考虑<body>(或者<html>)是否具有tabIndex属性,因此实际上可以集中注意力。如果你正在编写一个库或某些东西,并希望它是健壮的,你应该以某种方式处理它。


这是一个(重型气流)“单线”版本获得聚焦元素,这在概念上更复杂,因为你必须知道短路,你知道,它显然不适合在一条线上,假设你希望它具有可读性。 我不打算推​​荐这个。但是,如果你是一个1337 hax0r,idk ......就在那里。 如果你不介意在某些情况下获得|| null,你也可以删除false部分。 (如果nulldocument.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;
});

您可以使用非事件方式修复初始状态假设,但是您可能只是使用它。


14
投票

如果没有可聚焦元素聚焦,document.activeElement可能会默认为<body>元素。此外,如果元素被聚焦并且浏览器窗口模糊,activeElement将继续保持聚焦元素。

如果不希望这两种行为中的任何一种,请考虑基于CSS的方法:document.querySelector( ':focus' )


10
投票

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

9
投票

我在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 docs的位置。我已经使用Chrome,FF和IE 7+进行了测试。请注意,要在IE中工作,<!DOCTYPE...必须存在于html页面上。这是一个假设您已为具有焦点的元素指定了id的示例:

$(":focus").each(function() {
  alert($(this).attr("id") + " has focus!");
});
© www.soinside.com 2019 - 2024. All rights reserved.