סיכום
<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
- דפוס תיבת סימון בגרסה 1.1 של שיטות העבודה לעריכת ARIA
- מה אפשר לעשות בעזרת ARIA?
- שימוש ב-Tabindex
הדגמה (דמו)
צפייה בהדגמה בזמן אמת ב-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('הודעה-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);
משתמש יכול להגדיר מאפיין במופע של רכיב לפני שאב הטיפוס שלו קושר למחלקה הזו. השיטה _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. זה מקום טוב לבצע בו פעולות כמו הפצת קובצי עזר והסרת פונקציות event listener.
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);
})();