Podsumowanie
<howto-checkbox>
reprezentuje opcję wartości logicznej w formularzu. Najczęściej jest to pole wyboru dwutypowe, które pozwala użytkownikowi przełączać się między 2 opcjami: zaznaczoną i niezaznaczoną.
Element próbuje samodzielnie zastosować atrybuty role="checkbox"
i tabindex="0"
przy jego tworzeniu. Atrybut role
pomaga technologii wspomagającej osoby z niepełnosprawnością, na przykład czytnika ekranu, informować użytkownika o tym, jaką kontrolę mają.
Atrybut tabindex
uwzględnia element w kolejności tabulacji, dzięki czemu można go naciskać i działać z klawiaturą. Aby dowiedzieć się więcej na te 2 tematy, przeczytaj artykuły Co może robić ARIA? i Korzystanie z tabindex.
Zaznaczenie tego pola wyboru powoduje dodanie atrybutu wartości logicznej checked
i ustawienie odpowiadającej mu właściwości checked
na wartość true
. Dodatkowo w zależności od stanu elementu ustawia on atrybut aria-checked
na "true"
lub "false"
. Kliknięcie pola wyboru za pomocą myszy lub spacji powoduje przełączenie zaznaczonego stanu.
To pole wyboru obsługuje też stan disabled
. Jeśli właściwość disabled
ma wartość true lub zostanie zastosowany atrybut disabled
, pole wyboru ustawia aria-disabled="true"
, usuwa atrybut tabindex
i zwraca zaznaczenie dokumentu, jeśli pole wyboru to bieżący parametr activeElement
.
Pole wyboru jest sparowane z elementem howto-label
, aby mieć pewność, że ma ono ułatwioną nazwę.
Dokumentacja
- Instrukcje: komponenty na GitHubie
- Wzorzec pola wyboru w metodach tworzenia ARIA 1.1
- Co potrafi ARIA?
- Korzystanie z tabindex
Wersja demonstracyjna
Zobacz prezentację na żywo w GitHubie
Przykład użycia
<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>
Kod
(function() {
Określaj kody klawiszy ułatwiające obsługę zdarzeń klawiatury.
const KEYCODE = {
SPACE: 32,
};
Klonowanie treści z elementu <template>
jest wydajniejsze niż użycie innerHTML, ponieważ pozwala to uniknąć dodatkowych kosztów analizy 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'];
}
Konstruktor elementu jest uruchamiany przy każdym utworzeniu nowej instancji. Instancje są tworzone przez analizowanie kodu HTML, wywoływanie elementu document.createElement('howto-checkbox') lub wywołanie nowego HowToCheckbox(). Konstruktor jest dobrym miejscem do tworzenia obiektu shadow DOM, ale unikaj dotykania żadnych atrybutów i elementów podrzędnych interfejsu Light DOM, ponieważ mogą one jeszcze nie być dostępne.
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
uruchamia się, gdy element zostanie wstawiony do modelu DOM. Jest to dobre miejsce do ustawienia początkowego stanu role
i tabindex
, stanu wewnętrznego oraz instalacji detektorów zdarzeń.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
Użytkownik może ustawić właściwość w wystąpieniu elementu, zanim jego prototyp zostanie połączony z klasą. Metoda _upgradeProperty()
sprawdzi właściwości instancji i przeprowadzi je za pomocą odpowiednich ustawień ustawiających klasy. Więcej informacji znajdziesz w sekcji dotyczącej leniwych właściwości.
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()
uruchamia się, gdy element zostanie usunięty z DOM. To świetne miejsce, by zrobić porządek, np. zwolnić pliki referencyjne i usunąć detektory zdarzeń.
disconnectedCallback() {
this.removeEventListener('keyup', this._onKeyUp);
this.removeEventListener('click', this._onClick);
}
Właściwości i odpowiadające im atrybuty powinny się replikować. Metoda ustawiająca w przypadku zaznaczonych właściwości obsługuje wartości prawda/fałsz i odzwierciedla ich stan w atrybucie. Więcej informacji znajdziesz w sekcji dotyczącej unikania ponawiania próśb.
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');
}
Funkcja attributeChangedCallback()
jest wywoływana, gdy zmieni się dowolny z atrybutów w tablicy zaobserwowanej. To dobre miejsce do radzenia sobie z efektami ubocznymi, takimi jak ustawianie atrybutów 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);
Atrybut tabindex
nie umożliwia pełnego usunięcia możliwości zaznaczenia elementu. Elementy z atrybutem tabindex=-1
nadal można zaznaczyć, używając myszy lub wywołując metodę focus()
. Aby mieć pewność, że element jest wyłączony i nie można go zaznaczyć, usuń atrybut tabindex
.
if (hasValue) {
this.removeAttribute('tabindex');
Jeśli zaznaczony jest obecnie ten element, cofnij jego zaznaczenie, wywołując metodę HTMLElement.blur()
this.blur();
} else {
this.setAttribute('tabindex', '0');
}
break;
}
}
_onKeyUp(event) {
Nie stosuj skrótów modyfikujących, które zwykle są używane w technologiach wspomagających osoby z niepełnosprawnością.
if (event.altKey)
return;
switch (event.keyCode) {
case KEYCODE.SPACE:
event.preventDefault();
this._toggleChecked();
break;
Pozostałe naciśnięcie klawisza jest ignorowane i jest przekazywane z powrotem do przeglądarki.
default:
return;
}
}
_onClick(event) {
this._toggleChecked();
}
_toggleChecked()
wywołuje zaznaczoną metodę ustawiania i odwraca jej stan. Funkcja _toggleChecked()
jest wywoływana tylko przez działanie użytkownika, więc wysyła też zdarzenie zmiany. To zdarzenie wyświetla się jako dymki, aby naśladować natywne działanie usługi <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);
})();