来自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。