12

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

现在假设我想要将文档的一部分显示为模式对话框,并且我不希望用户被对话框之外的任何内容分散注意力。我希望 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>

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

4

3 回答 3

12

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

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

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

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

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

困难的部分是知道哪些元素是可标签的。由于 tabbable 元素都是没有 的可聚焦元素tabindex="-1",那么我们需要知道哪些元素是可聚焦的。由于没有属性来确定一个元素是否可聚焦,jQuery 通过硬编码以下情况来做到这一点:

  • input, select, textarea, button, 和object未被禁用的元素。
  • a以及area具有href或具有 set 数值的元素tabindex
  • 任何具有 set 数值的元素tabindex

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

  • 它的祖先都不是display: none
  • visibility的计算值为visible。这意味着要visibility设置的最近祖先的值必须为visible。如果没有祖先visibility设置,则计算值为visible

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

于 2011-10-24T05:49:35.953 回答
1

jQuery UI 对话框通过捕获keydown事件、检查它们是否用于 TAB,然后手动聚焦正确的元素来实现这一点。

于 2011-10-24T03:06:29.600 回答
0

jqModal jQuery 插件通过将选项设置为 true 来实现这一点modal。此页面上带有表单的示例应显示它。我记得通过代码查看发生了什么,你可以用普通的 JS 很容易地做到这一点。

于 2011-10-24T03:01:30.357 回答