Краткое содержание
<howto-checkbox>
представляет собой логический параметр в форме. Наиболее распространенным типом флажка является двойной тип, который позволяет пользователю переключаться между двумя вариантами выбора: отмеченным и снятым.
Элемент пытается самостоятельно применить атрибуты role="checkbox"
и tabindex="0"
при первом создании. Атрибут role
помогает вспомогательным технологиям, таким как программа чтения с экрана, сообщать пользователю, что это за элемент управления. Атрибут tabindex
включает элемент в порядок табуляции, что делает его доступным для фокусировки и управления с клавиатуры. Чтобы узнать больше об этих двух темах, ознакомьтесь со статьей Что может сделать ARIA? и Использование tabindex .
Когда флажок установлен, он добавляет логический атрибут checked
и присваивает соответствующему свойству checked
значение true
. Кроме того, элемент устанавливает для атрибута aria-checked
значение "true"
или "false"
в зависимости от его состояния. Нажатие на флажок с помощью мыши или клавиши пробела переключает эти отмеченные состояния.
Флажок также поддерживает disabled
состояние. Если для свойства disabled
установлено значение true или применен атрибут disabled
, флажок устанавливает aria-disabled="true"
, удаляет атрибут tabindex
и возвращает фокус документу, если флажок является текущим activeElement
.
Флажок связан с элементом howto-label
чтобы обеспечить доступное имя .
Ссылка
- HowTo: Компоненты на GitHub
- Шаблон флажка в методах разработки ARIA 1.1
- Что может сделать АРИЯ?
- Использование табиндекса
Демо
Посмотреть живую демонстрацию на GitHub
Пример использования
<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') или вызова new HowToCheckbox(); Конструктор — хорошее место для создания теневого DOM, однако вам следует избегать касания каких-либо атрибутов или дочерних элементов светлого 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()
проверит наличие всех свойств экземпляра и пропустит их через соответствующие установщики классов. Дополнительную информацию см. в разделе ленивых свойств .
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);
}
Свойства и соответствующие им атрибуты должны отражать друг друга. Установщик свойства для проверенного обрабатывает значения правдивости/ложности и отображает их в состоянии атрибута. Дополнительные сведения см. в разделе «Избежание повторного входа» .
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');
}
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()
вызывает проверенный установщик и меняет его состояние. Поскольку _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);
})();