摘要
<howto-checkbox>
表示表单中的布尔选项。最常见的类型
是双重类型,让用户可以在
选中和取消选中。
该元素会尝试自行应用属性 role="checkbox"
和
tabindex="0"
。role
属性提供辅助功能
屏幕阅读器等技术告诉用户这是什么类型的控制。
tabindex
属性用于为元素启用 Tab 键顺序,使其成为键盘布局
可聚焦且可操作如需详细了解这两个主题,请参阅
ARIA 可以做什么?和使用 tabindex。
勾选该复选框后,系统会添加一个 checked
布尔值属性,并将
与 true
对应的 checked
属性。此外, 元素设置了一个
aria-checked
属性设为 "true"
或 "false"
,具体取决于其
状态。使用鼠标或空格键点击该复选框即可切换这些状态
选中状态
该复选框还支持 disabled
状态。如果 disabled
属性
设置为 true 或应用 disabled
属性时,该复选框会将
aria-disabled="true"
,移除 tabindex
属性并返回焦点
如果复选框是当前的 activeElement
,则应用于文档。
该复选框会与 howto-label
元素配对,以确保其具有
无障碍名称。
参考
演示
用法示例
<style>
howto-checkbox {
vertical-align: middle;
}
howto-label {
vertical-align: middle;
display: inline-block;
font-weight: bold;
font-family: sans-serif;
font-size: 20px;
margin-left: 8px;
}
</style>
<howto-checkbox id="join-checkbox"></howto-checkbox>
<howto-label for="join-checkbox">Join Newsletter</howto-label>
代码
(function() {
定义按键代码以帮助处理键盘事件。
const KEYCODE = {
SPACE: 32,
};
从 <template>
元素克隆内容比使用 innerHTML 的性能更高,因为这样可以避免额外的 HTML 解析开销。
const template = document.createElement('template');
template.innerHTML = `
<style>
:host {
display: inline-block;
background: url('../images/unchecked-checkbox.svg') no-repeat;
background-size: contain;
width: 24px;
height: 24px;
}
:host([hidden]) {
display: none;
}
:host([checked]) {
background: url('../images/checked-checkbox.svg') no-repeat;
background-size: contain;
}
:host([disabled]) {
background:
url('../images/unchecked-checkbox-disabled.svg') no-repeat;
background-size: contain;
}
:host([checked][disabled]) {
background:
url('../images/checked-checkbox-disabled.svg') no-repeat;
background-size: contain;
}
</style>
`;
class HowToCheckbox extends HTMLElement {
static get observedAttributes() {
return ['checked', 'disabled'];
}
每次创建新实例时,都会运行元素的构造函数。可通过解析 HTML、调用 document.createElement('howto-checkbox') 或调用新的 HowToCheckbox(); 来创建实例。构造函数是创建 shadow DOM 的理想位置,但您应避免触摸任何属性或 light DOM 子项,因为它们可能还不可用。
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
,在元素插入 DOM 时触发。它非常适合设置初始 role
、tabindex
、内部状态和安装事件监听器。
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
用户可以在元素的原型连接到此类之前,在元素的实例上设置属性。_upgradeProperty()
方法将检查是否有任何实例属性,并通过适当的类 setter 运行这些属性。如需了解详情,请参阅延迟属性部分。
this._upgradeProperty('checked');
this._upgradeProperty('disabled');
this.addEventListener('keyup', this._onKeyUp);
this.addEventListener('click', this._onClick);
}
_upgradeProperty(prop) {
if (this.hasOwnProperty(prop)) {
let value = this[prop];
delete this[prop];
this[prop] = value;
}
}
disconnectedCallback()
,在元素从 DOM 中移除时触发。非常适合执行清理工作,例如释放引用和移除事件监听器。
disconnectedCallback() {
this.removeEventListener('keyup', this._onKeyUp);
this.removeEventListener('click', this._onClick);
}
属性及其对应的属性应相互镜像。已检查的属性 setter 会处理 true/falsy 值,并将这些值反映到属性的状态。如需了解详情,请参阅避免再次进入部分。
set checked(value) {
const isChecked = Boolean(value);
if (isChecked)
this.setAttribute('checked', '');
else
this.removeAttribute('checked');
}
get checked() {
return this.hasAttribute('checked');
}
set disabled(value) {
const isDisabled = Boolean(value);
if (isDisabled)
this.setAttribute('disabled', '');
else
this.removeAttribute('disabled');
}
get disabled() {
return this.hasAttribute('disabled');
}
当 observeAttributes 数组中的任何属性发生更改时,系统会调用 attributeChangedCallback()
。这是处理副作用(如设置 ARIA 属性)的绝佳位置。
attributeChangedCallback(name, oldValue, newValue) {
const hasValue = newValue !== null;
switch (name) {
case 'checked':
this.setAttribute('aria-checked', hasValue);
break;
case 'disabled':
this.setAttribute('aria-disabled', hasValue);
tabindex
属性未提供从元素完全移除可聚焦性的方法。具有 tabindex=-1
的元素仍然可以使用鼠标或通过调用 focus()
进行聚焦。若要确保某个元素已停用且不可聚焦,请移除 tabindex
属性。
if (hasValue) {
this.removeAttribute('tabindex');
如果焦点当前位于此元素上,请调用 HTMLElement.blur()
方法取消聚焦
this.blur();
} else {
this.setAttribute('tabindex', '0');
}
break;
}
}
_onKeyUp(event) {
不要处理辅助技术通常使用的修饰符快捷键。
if (event.altKey)
return;
switch (event.keyCode) {
case KEYCODE.SPACE:
event.preventDefault();
this._toggleChecked();
break;
系统将忽略任何其他按键操作,并将其传递回浏览器。
default:
return;
}
}
_onClick(event) {
this._toggleChecked();
}
_toggleChecked()
会调用选中的 setter 并翻转其状态。由于 _toggleChecked()
仅由用户操作引起,因此还会分派更改事件。此事件气泡是为了模拟 <input type=checkbox>
的原生行为。
_toggleChecked() {
if (this.disabled)
return;
this.checked = !this.checked;
this.dispatchEvent(new CustomEvent('change', {
detail: {
checked: this.checked,
},
bubbles: true,
}));
}
}
customElements.define('howto-checkbox', HowToCheckbox);
})();