סיכום
<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
- מה אפשר לעשות בעזרת ARIA?
- שימוש באינדקס של כרטיסיות
הדגמה (דמו)
צפייה בהדגמה בזמן אמת ב-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'];
}
ה-constructor של הרכיב מופעל בכל פעם שיוצרים מכונה חדשה. מכונות נוצרות על ידי ניתוח HTML, קריאה ל- document.createElement('US-checkbox') או קריאה ל-HowToCheckbox(); ה-constructor הוא מקום טוב ליצירת DOM של צללים, אבל כדאי להימנע מנגיעה במאפיינים או צאצאים של DOM קל כי הם עדיין לא זמינים.
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
מופעל כשמוסיפים את הרכיב ל-DOM. זהו מקום טוב להגדרת פונקציות role
, tabindex
והמצב הפנימי הראשוניות והתקנת פונקציות event listener.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
משתמש יכול להגדיר מאפיין במופע של אלמנט, לפני שאבי הטיפוס שלו חובר למחלקה הזו. ה-method _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);
}
הנכסים והמאפיינים התואמים שלהם צריכים לשקף זה את זה. הפרמטר setter של המאפיין (property) עבור מסומן מטפל בערכי truthy/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');
}
הפונקציה 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');
אם המיקוד הוא כרגע ברכיב הזה, אפשר לבטל את המיקוד באמצעות קריאה ל-method 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);
})();