javascript 仅通过特定元素的可聚焦后代进行选项卡的最简单方法?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7870544/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-26 01:35:28  来源:igfitidea点击:

Simplest way to tab only through focusable descendants of a particular element?

javascripthtmlfocustabindex

提问by Chris Calo

Let's say I have a document full of focusable elements, either because they are innately focusable (like <input type="text">) or because they have tabindex="0"or the like.

假设我有一个充满可聚焦元素的文档,要么是因为它们天生具有可聚焦性(如<input type="text">),要么是因为它们具有tabindex="0"或类似的特性。

Now let's say there's a section of my document that I want to display as a modal dialog box, and I don't want the user to be distracted by anything outside the dialog box. I would like for the tab key to cycle only through focusable elements inside the container element for the dialog box. What is the simplest way to do this?

现在假设我想将文档的一部分显示为模式对话框,并且我不希望用户被对话框外的任何内容分散注意力。我希望 tab 键只能在对话框的容器元素内的可聚焦元素之间循环。什么是最简单的方法来做到这一点?

If possible, I am looking for a solution that doesn't care what the contents of the dialog or the rest of the page are and doesn't try to modify them. That is, I don't want to make the elements outside of the dialog not focusable, for example. First, this requires making a reversible change and keeping track of state. Second, this requires knowing all the possible ways an element could be made focusable. This feels messy, fragile, and unscalable to me.

如果可能,我正在寻找一种解决方案,它不关心对话框的内容或页面的其余部分是什么并且不尝试修改它们。也就是说,例如,我不想让对话框外的元素不可聚焦。首先,这需要进行可逆的更改并跟踪状态。其次,这需要了解使元素可聚焦的所有可能方式。对我来说,这感觉凌乱、脆弱且无法扩展。

My first attempt looks like this, but works only in the forward direction (pressing Tab). It doesn't work in the reverse direction (pressing Shift+Tab).

我的第一次尝试看起来像这样,但仅适用于向前方向(按 Tab)。它在相反方向不起作用(按 Shift+Tab)。

<div>Focusable stuff outside the dialog.</div>
<div class="dialog" tabindex="0">
  <!-- Focus should be trapped inside this dialog while it's open -->
  <div class="content">
    Form contents and focusable stuff here.
  </div>
  <div class="last-focus" tabindex="0" onfocus="this.parentNode.focus()"></div>
</div>
<div>More focusable stuff outside the dialog.</div>

I'd rather see pure JavaScript solutions. If there is a means of doing this with a library such as jQuery, I would prefer a link to the library code that does this.

我宁愿看到纯 JavaScript 解决方案。如果有一种使用 jQuery 之类的库来执行此操作的方法,我更喜欢指向执行此操作的库代码的链接。

采纳答案by Chris Calo

In the interest of completeness, I'm taking the link to jQuery UI dialogthat @Domenic provided and filling in the details.

为了完整起见,我将链接到@Domenic 提供的jQuery UI 对话框并填写详细信息。

To implement this in the jQuery fashion requires two things:

要以 jQuery 方式实现这一点,需要做两件事:

  1. Listening for Tabor Shift+Tab(on keydown) for the modal element that should trap focus. This is the only means of moving focus via the keyboard. (If you want to prevent mouse interaction with the rest of the document, that is a separate problem solved by covering it with an element to prevent any mouse events from getting through.)

  2. Finding all tabbable elements inside the modal element. These are a subset of all focusable elements, excluding those that have tabindex="-1".

  1. 侦听TabShift+Tab(on keydown) 应捕获焦点的模态元素。这是通过键盘移动焦点的唯一方法。(如果你想阻止鼠标与文档的其余部分交互,这是一个单独的问题,通过用一个元素覆盖它来防止任何鼠标事件通过。)

  2. 查找模态元素内的所有可选项卡元素。这些是所有可聚焦元素的子集,不包括具有tabindex="-1".

Tabgoes forward. Shift+Tabgoes backwards. Any time Tabis pressed while the last tabbable element in the modal element is focused, the first should receive focus. Similarly, any time Shift+Tabis pressed while the first tabbable element is focused, the last should receive focus. This will keep focus inside the modal element.

Tab前进。Shift+Tab倒退。Tab当模态元素中的最后一个 tabbable 元素被聚焦时,任何时候按下,第一个应该获得焦点。类似地,Shift+Tab在第一个可选项卡元素获得焦点时按下任何时间,最后一个应该获得焦点。这将使焦点保持在模态元素内。

The hard part is knowing which elements are tabbable. Since tabbable elements are all focusable elements that don't have tabindex="-1", then we need to know know which elements are focusable. Since there's no property to determine if an element is focusable, jQuery does it by hard-coding the following cases:

困难的部分是知道哪些元素是可选项卡的。由于 tabbable 元素都是没有的可聚焦元素tabindex="-1",那么我们需要知道哪些元素是可聚焦的。由于没有属性来确定元素是否可聚焦,jQuery 通过对以下情况进行硬编码来实现

  • input, select, textarea, button, and objectelements that aren't disabled.
  • aand areaelements that have an hrefor have a numerical value for tabindexset.
  • any element that has a numerical value for tabindexset.
  • inputselecttextareabuttonobject未禁用的元素。
  • aarea具有href或具有tabindex集合数值的元素。
  • 任何具有tabindex集合数值的元素。

It's not enough to check for these three cases. jQuery goes on to ensure that the element is visible. This means both of the following must be true:

仅检查这三种情况是不够的。jQuery 继续确保元素可见。这意味着以下两项都必须为真:

  • None of its ancestors are display: none.
  • The computed value of visibilityis visible. This means that the nearest ancestor to have visibilityset must have a value of visible. If no ancestor has visibilityset, then the computed value is visible.
  • 它的祖先都不是display: none
  • 的计算值visibilityvisible。这意味着要visibility设置的最近祖先的值必须为visible。如果没有visibility设置祖先,则计算值为visible

It should be noted that jQuery's :visibleselectordoes not look correct for this implementation because it says "elements with visibility: hidden…are considered to be visible," but they are not focusable.

应该注意的是,jQuery 的:visible选择器对于这个实现看起来并不正确,因为它说“带有visibility: hidden……的元素被认为是可见的”,但它们不是可聚焦的。

回答by Domenic

The jQuery UI dialogdoes this by capturing keydownevents, checking if they are for TAB or not, then manually focusing the correct element.

jQuery UI 对话框通过捕获keydown事件,检查它们是否用于 TAB,然后手动聚焦正确的元素来完成此操作。

回答by Moin Zaman

The jqModaljQuery plugin does this out of the box by setting the modaloption to true. The examples on this page with forms should show it. I remember going through the code to see what was happening and you could do it quite easily with plain JS.

jqModaljQuery插件通过设置执行此开箱modal选项设置为true。此页面上的带有表单的示例应该会显示它。我记得通过代码看看发生了什么,你可以用普通的 JS 很容易地做到这一点。