如何使自定义 Web 组件可聚焦?
How to make a custom web component focusable?
我正在写一个 custom web component 是为了互动。我怎样才能告诉浏览器这个自定义组件应该获得焦点?
我希望我的自定义元素...
- 可以聚焦(通过标签导航);
- 聚焦时可以接收按键;
- 可以匹配到
:focus
pseudo-selector。
我没有使用任何外部库,只是普通的 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
也可以。 keydown
和 keyup
事件有效,尽管 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>
并不像看起来那么简单(尤其要考虑按钮更改的行高)
我正在写一个 custom web component 是为了互动。我怎样才能告诉浏览器这个自定义组件应该获得焦点?
我希望我的自定义元素...
- 可以聚焦(通过标签导航);
- 聚焦时可以接收按键;
- 可以匹配到
:focus
pseudo-selector。
我没有使用任何外部库,只是普通的 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
也可以。 keydown
和 keyup
事件有效,尽管 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>
并不像看起来那么简单(尤其要考虑按钮更改的行高)