【问题标题】:How to make a custom web component focusable?如何使自定义 Web 组件具有焦点?
【发布时间】:2015-09-05 20:07:58
【问题描述】:

我正在写一个custom web component,它是为了互动。如何告诉浏览器这个自定义组件应该获得焦点?

我希望我的自定义元素……

  • 可以聚焦(通过标签导航);
  • 聚焦时可以接收按键;
  • 可以与:focus pseudo-selector匹配。

我没有使用任何外部库,只是普通的 HTML5 API。

【问题讨论】:

    标签: html web-component


    【解决方案1】:

    基于我在this question 中找到的this demo,我有这个答案:

    只需将tabindex 属性添加到您想要获得焦点的元素即可。

    // Add this to createdCallback function:
    if (!this.hasAttribute('tabindex')) {
        // Choose one of the following lines (but not both):
        this.setAttribute('tabindex', 0);
        this.tabIndex = 0;
    }
    // The browser automatically syncs tabindex attribute with .tabIndex property.
    

    点击元素将获得焦点。按选项卡将起作用。在 CSS 中使用 :focus 也可以。 keydownkeyup 事件有效,尽管 keypress 无效(但 it's deprecated anyway)。在 Chrome 44 和 Firefox 40 上测试。

    还要注意this.tabIndex即使缺少HTML属性也会返回-1,但这与设置tabindex="1"有不同的行为:

    • <foo></foo>:没有tabindex 属性,该元素不可聚焦。
    • <foo tabindex="-1"></foo>:该元素无法通过选项卡导航访问,但仍可通过单击获得焦点。

    参考资料:

    【讨论】:

      【解决方案2】:

      @Denilson,我想为您提供更多信息。

      正如您所说,this.tabIndex = 0 在您的 web 组件不包含可聚焦元素时有效。如果是这样,它会变得更加复杂。

      例如,如果您的组件包含一个或多个输入,则首先“整个”组件获得焦点,然后才在切换时,每个内部输入逐个获得焦点。这通常不是你想要的。通常,当组件获得焦点时,这意味着它的第一个输入会立即获得焦点。

      此外,还有一个反向跳格问题。如果您的第一个输入具有焦点并且您按 SHIFT-TAB,则“整个”组件将获得焦点,并且您必须按两次 SHIFT-TAB 才能移动到上一个元素。

      我发现这可以解决所有焦点和标签问题:

      // At first, the component may get focus and accept tabbing.
      createdCallback = function () { this.tabIndex = 0; }
      
      // When the component gets focus, pass focus to the first inner element.
      // Then make tabindex -1 so that the component may still get focus, but does NOT accept tabbing.
      focus = function (e) { firstFocusableInnerElement.focus(); this.tabIndex = -1; }
      
      // When we completely left the component, then component may accept tabbing again.
      blur = function (e) { this.tabIndex = 0; }
      

      注意:截至目前(2015 年 9 月),如果内部元素获得焦点,则 :focus 伪选择器不会匹配“整个”元素(仅在 Chrome 中测试)。如果发现这种行为是完全错误的。 focus 事件被触发,而 blur 事件未被触发。所以元素应该有焦点,对吧?我希望他们将来能改变这一点。

      【讨论】:

      • 我想这是可行的,因为当内部元素聚焦(或失去焦点)时,事件本身会冒泡,调用您的处理程序。而且……如果外部元素不可聚焦,会有什么行为?内部的也可以聚焦吗?你有任何现场演示可用吗?
      • Shadow DOM 有一个称为“事件重定向”的功能,它可以在事件冒泡时更改事件的目标,这样目标总是在接收元素的 light DOM 中。即,源自影子 DOM 内部节点的事件被重新定位,因此它们似乎来自影子主机。如果元素已经拥有焦点,则内部元素的焦点事件不会越界。
      • 感谢 cmets!回答我自己的问题:外部(轻 DOM)tabindex 不会影响内部(影子 DOM)tabindex。这意味着即使外部元素不是,内部元素也是可聚焦的。 (现在想起来,感觉有点明显。)
      • 虽然这看起来很麻烦而且很老套,但这是我发现的唯一可行的方法。谢谢
      【解决方案3】:

      如果可能且合适的话,我使用的一种非常实用的方法就是在我的自定义元素周围放置一个<button type='button'>
      这可能不适合您的解决方案,无论如何我都会为其他进入这个问题/问题的人提到它。

      它处理所有焦点问题,包括焦点矩形等。

      驯服<button> 的工作比看起来要少(尤其要考虑按钮更改的行高)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-11-16
        • 2017-03-24
        相关资源
        最近更新 更多