仅通过特定元素的可聚焦后代进行制表的最简单方法是什么?

Chr*_*alo 12 html javascript focus tabindex

假设我有一个充满可聚焦元素的文档,要么是因为它们天生具有可聚焦性(如<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>
Run Code Online (Sandbox Code Playgroud)

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

Chr*_*alo 12

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

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

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

  2. 查找模态元素中的所有可列表元素.这些是所有可聚焦元素的子集,不包括那些元素tabindex="-1".

Tab前进.Shift+Tab倒退.Tab在模式元素中的最后一个tabbable元素被聚焦时按下任何时间,第一个应该获得焦点.同样,Shift+Tab在第一个tabbable元素被聚焦时按下任何时间,最后一个应该获得焦点.这将使焦点保持在模态元素内.

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

  • input,select,textarea,button,和object没有被禁用的元素.
  • aarea具有href或具有tabindexset 的数值的元素.
  • 任何具有tabindexset 数值的元素.

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

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

应该注意的是,jQuery的:visible选择器对于这个实现看起来并不正确,因为它表示"具有visibility: hidden...的元素被认为是可见的",但它们不可聚焦.