Javascript 仅通过特定元素的可聚焦子体进行制表的最简单方法?

Javascript 仅通过特定元素的可聚焦子体进行制表的最简单方法?,javascript,html,focus,tabindex,Javascript,Html,Focus,Tabindex,假设我有一个充满可聚焦元素的文档,要么因为它们是天生可聚焦的(比如),要么因为它们有tabindex=“0”等等 现在让我们假设我的文档中有一部分我想显示为一个模式对话框,我不想让用户被对话框之外的任何东西分心。我希望tab键只在对话框的容器元素内的可聚焦元素之间循环。最简单的方法是什么 如果可能的话,我正在寻找一种解决方案,它不关心对话框或页面其余部分的内容,也不试图修改它们。也就是说,例如,我不想使对话框外部的元素不可聚焦。首先,这需要做出可逆的改变并跟踪状态。其次,这需要了解使元素可聚焦的

假设我有一个充满可聚焦元素的文档,要么因为它们是天生可聚焦的(比如
),要么因为它们有
tabindex=“0”
等等

现在让我们假设我的文档中有一部分我想显示为一个模式对话框,我不想让用户被对话框之外的任何东西分心。我希望tab键只在对话框的容器元素内的可聚焦元素之间循环。最简单的方法是什么

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

我的第一次尝试看起来像这样,但仅在前进方向上有效(按Tab键)。它在相反方向上不工作(按Shift+Tab)

对话框外的可聚焦内容。
在这里形成内容和可聚焦的内容。
在对话框之外有更多可聚焦的东西。

我宁愿看到纯JavaScript解决方案。如果有一种方法可以在jQuery这样的库中实现这一点,我更希望有一个指向实现这一点的库代码的链接。

jQuery插件通过将
modal
选项设置为true来实现这一点。本页上的示例和表单应能说明这一点。我记得我仔细阅读了代码,看看发生了什么,你可以用简单的JS轻松地完成

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

为了完整性,我将获取提供的@Domenic链接并填写详细信息

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

  • 侦听应捕获焦点的模态元素的
    选项卡
    Shift+Tab
    (在
    键下
    )。这是通过键盘移动焦点的唯一方法。(如果要防止鼠标与文档的其余部分交互,这是一个单独的问题,可以通过使用元素覆盖它来解决,以防止任何鼠标事件通过。)

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

  • 选项卡向前移动<代码>Shift+Tab
    向后移动。当模态元素中的最后一个tabbable元素被聚焦时,任何时候按下
    Tab
    ,第一个应接收聚焦。类似地,当第一个tabbable元素被聚焦时,按下Shift+Tab时,最后一个应接收聚焦。这将在模态元素内保持焦点

    困难的部分是知道哪些元素是可标记的。因为tabbable元素都是可聚焦的元素,没有
    tabindex=“-1”
    ,所以我们需要知道哪些元素是可聚焦的。由于没有属性来确定元素是否可聚焦,jQuery通过以下方式来确定:

    • 输入
      选择
      文本区
      按钮
      ,以及未禁用的
      对象
      元素
    • a
      区域
      元素,这些元素具有
      href
      选项卡索引
      集的数值
    • 具有
      tabindex
      集合数值的任何元素
    仅仅检查这三个病例是不够的。jQuery继续确保元素是可见的。这意味着以下两项都必须为真:

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

    应该注意的是,这个实现看起来不正确,因为它说“具有
    可见性的元素:隐藏的
    …被认为是可见的”,但它们不可聚焦。

    谢谢,Moin。它看起来像示例4,试图在对话框中捕获焦点,但并不完全有效(有一个获取焦点的“JavaScript”链接)。尽管如此,它看起来很有希望,但我不确定它是如何实现这一目标的。你能告诉我处理这个部分的来源吗?在插件中搜索大写字母“L”。它们似乎是
    keypress
    keydown
    mousedown
    事件。最简单的方法是将“focusin”事件绑定到文档。在事件处理程序中,检查当前焦点是否在对话框中。如果没有,则将焦点重新应用于对话框中的某个元素。对话框关闭后,别忘了删除文档上的事件绑定。@Bjorn,听起来您需要使用计时器来聚焦与
    聚焦事件中的目标元素不同的元素。虽然这样做的代码较少,但如果没有把握好时间,听起来可能有问题。如果你让它工作起来,你应该发布一个单独的答案。你不需要定时器,你只需要响应聚焦事件。我已经让它工作了,但是我的代码依赖于jQuery/Backbone/marionete,所以如果您使用不同的框架,就没有一个明确的答案。
    
    <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>