如何使自定义 Web 组件可聚焦?

How to make a custom web component focusable?

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

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

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

基于this demo that I found in this question,我有这个答案:

只需将 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 returns -1 即使缺少 HTML 属性,但这与设置 tabindex="1" 的行为不同:

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

参考文献:

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

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

例如,如果您的组件包含一个或多个输入,那么 "whole" 组件首先获得焦点,只有稍后,当使用 Tab 键时,每个内部输入才一个接一个地获得焦点。这通常不是您想要的。通常,当组件获得焦点时,这应该意味着它的第一个输入立即获得焦点。

此外,还有反向跳格问题。如果您的第一个输入有焦点并且您按下 SHIFT-TAB,那么 "whole" 组件获得焦点,并且您必须按两次 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 月),如果内部元素获得焦点,则 "whole" 元素与 :focus 伪元素不匹配-选择器(仅在 Chrome 中测试)。如果发现这种行为是完全错误的。 focus 事件被触发,而 blur 事件没有。所以元素应该有焦点,对吧?我希望他们将来能改变这一点。

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

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

驯服一个 <button> 并不像看起来那么简单(尤其要考虑按钮更改的行高)