【问题标题】:Is there a jQuery selector to get all elements that can get focus?是否有一个 jQuery 选择器来获取所有可以获得焦点的元素?
【发布时间】:2011-10-05 22:31:53
【问题描述】:

This answer 告诉哪些 HTML 元素可以接收焦点。是否有与这些元素完全匹配的 jQuery 选择器?

目前我只使用$('input,select,textarea,a'),但我想知道是否有更精确的东西。

【问题讨论】:

标签: javascript jquery


【解决方案1】:

来自other SO answer referred to by the OP

当今的浏览器在 HTMLElement 上定义 focus(),...

所以,这意味着将focus 测试为元素的成员是有效的,因为所有元素都会拥有它,无论它们是否真的接受焦点与否。

...但是一个元素实际上不会获得焦点,除非它是以下之一:

  • 带有href的HTMLAnchorElement/HTMLAreaElement
  • HTMLInputElement/HTMLSelectElement/HTMLTextAreaElement/HTMLButtonElement 但不是disabled(如果你尝试,IE 实际上会给你一个错误), 出于安全原因,文件上传存在异常行为
  • HTMLIFrameElement(尽管聚焦它并没有什么用处)。 可能还有其他嵌入元素,我还没有全部测试过。
  • 任何带有tabindex 的元素

那么,在jQuery Selector 中明确命名所有这些内容怎么样?

$('a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]')

更新 #1

updated your jsFiddle here。它似乎有效。

我还在上面的列表中添加了属性为 contenteditable 的元素。


更新 #2

正如@jfriend00 指出的那样,“根据使用情况,可能需要过滤掉不可见的元素”。为此,只需将.filter(':visible') 应用于从上述选择器生成的集合。


更新 #3

正如Xavin pointed out:jQuery UI 现在有一个选择器:focusable,它执行这个功能。如果您已经在使用 jQuery UI,那么这可能是要走的路。如果没有,那么您可能想要check out how jQuery UI does it。无论如何,jQuery UI 页面上:focusable 的描述很有帮助:

如果未禁用以下类型的元素,则它们是可聚焦的:输入、选择、文本区域、按钮和对象。如果锚点具有 href 或 tabindex 属性,则它们是可聚焦的。如果 area 元素位于命名地图内、具有 href 属性并且使用该地图有可见图像,则它们是可聚焦的。所有其他元素都可以仅根据它们的 tabindex 属性和可见性获得焦点。

所以,我上面提出的选择器很接近,但它没有考虑到一些细微差别。

这是从 jQuery UI 中提取的函数,稍作修改以使其独立。 (改编未经测试,但应该可以工作):

function focusable( element ) {
    var map, mapName, img,
        nodeName = element.nodeName.toLowerCase(),
        isTabIndexNotNaN = !isNaN( $.attr( element, "tabindex" ) );
    if ( "area" === nodeName ) {
        map = element.parentNode;
        mapName = map.name;
        if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
            return false;
        }
        img = $( "img[usemap=#" + mapName + "]" )[0];
        return !!img && visible( img );
    }
    return ( /input|select|textarea|button|object/.test( nodeName ) ?
        !element.disabled :
        "a" === nodeName ?
            element.href || isTabIndexNotNaN :
            isTabIndexNotNaN) &&
        // the element and all of its ancestors must be visible
        visible( element );

    function visible( element ) {
      return $.expr.filters.visible( element ) &&
        !$( element ).parents().addBack().filter(function() {
          return $.css( this, "visibility" ) === "hidden";
        }).length;
    }
}

注意:上述功能仍然依赖于 jQuery,但不应该需要 jQuery UI。

【讨论】:

  • 根据用途,可能需要过滤掉不可见的元素。
  • 也许没有更好的办法,但是这种代码的问题是它很脆弱。每次有新类型的可编辑元素或使某些东西可编辑的新属性时,都必须维护它。
  • @jfriend00 - 好点。我更新了我的答案以包含您的建议。
  • 目前在 JQUI 中的实现很好而且独立:github.com/jquery/jquery-ui/blob/master/ui/focusable.js
  • 大家不要忘记:not([tabindex=-1])。它在技术上是可聚焦的,但无法通过标签访问。
【解决方案2】:

您可以检查具有focus() 函数的元素:

$('*').each(function() {
  if(typeof this.focus == 'function') {
    // Do something with this element
  }
}) ;

编辑 再想一想,将*:visible 而不仅仅是* 作为大多数应用程序的选择器可能是有意义的。

【讨论】:

  • 绝对是要走的路。就显式选择器而言,我认为这是不可能的,因为 jQuery 选择器是基于 sizzlejs.com 构建的。
  • 除非,如果您阅读 OP 中链接的帖子,它会说:the only elements that have a focus() method are HTMLInputElement, HTMLSelectElement, HTMLTextAreaElement and HTMLAnchorElement. This notably omits HTMLButtonElement and HTMLAreaElement. 所以测试.focus() 不会这样做(显然)。
  • DOM 元素是宿主对象,它们不需要遵守 ECMAScript 的规则,因此它们对 typeof 运算符的响应可以是任何东西,包括抛出错误。在 IE 8 中,typeof element.focus 在文本输入中返回 object,因此上述测试将在大约 1:5 的浏览器中失败,可能更多。
  • 这是一个很酷的想法,但是当我测试它时,它似乎收集了 Chrome 14 中页面上的每个元素,甚至是不可编辑或不可聚焦的 div 和 span。测试结果见这里:jsfiddle.net/jfriend00/vHNSX
  • @jfriend00 - jsfiddle.net/vHNSX/4 -- 这是蛮力,但它有效。 (见下面我的回答)。
【解决方案3】:

另一个简单但完整的 jQuery 选择器可能是这个:

$('a[href], area[href], input, select, textarea, button, iframe, object, embed, *[tabindex], *[contenteditable]')
.not('[tabindex=-1], [disabled], :hidden')

【讨论】:

  • *前面的[tabindex]是不必要的
【解决方案4】:

我有一个相对简单的解决方案,它返回所有可选项卡的子项,按它们的选项卡顺序,而不使用 jQuery。

function tabbable(el) {
    return [].map.call(el.querySelectorAll([
        'input',
        'select',
        'a[href]',
        'textarea',
        'button',
        '[tabindex]'
    ]), function(el, i) { return { el, i } }).
        filter(function(e) {
            return e.el.tabIndex >= 0 && !e.el.disabled && e.el.offsetParent; }).
        sort(function(a,b) {
            return a.el.tabIndex === b.el.tabIndex ? a.i - b.i : (a.el.tabIndex || 9E9) - (b.el.tabIndex || 9E9); });
}

对于 IE,请考虑实施与 e.el.offsetParent 不同的可见性检查。 jQuery 可以在这里为您提供帮助。

如果您不需要对元素进行排序,请忽略对 sort() 的调用。

【讨论】:

    【解决方案5】:

    在 jQuery 中不存在您要查找的选择器。

    如果你已经在使用 jQueryUI,你可以使用:focusable 选择器。

    http://api.jqueryui.com/focusable-selector/

    【讨论】:

      【解决方案6】:

      您可能想尝试在捕获焦点事件的body 元素上设置焦点处理程序,而不是获取可聚焦元素的列表。

      $(document.body).on("focus", "*", function(e) {
          //Scroll to e.target
      });
      

      【讨论】:

      • 除非我们已经证明检查 this.focus 的类型不起作用。
      【解决方案7】:
      var allElementsThatCanBeFocused = $(':focusable');
      

      【讨论】:

      • :focusable 不是 jQuery 的一部分,而是 jQuery UI。
      【解决方案8】:

      了解元素是否支持特定类型的侦听器的一般测试是查看它是否具有相关属性,例如要测试对 focus 事件的支持,请使用:

      if ('focus' in element) {
        // element supports the focus event
      }
      

      但是,也有一些例外。查看How do you programmatically determine to which events an HTML object can listen for?的答案。

      【讨论】:

        猜你喜欢
        • 2022-01-16
        • 2021-11-10
        • 2010-12-31
        • 2023-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-15
        相关资源
        最近更新 更多