Tóm tắt
<howto-checkbox>
đại diện cho tuỳ chọn boolean trong một biểu mẫu. Loại hộp đánh dấu phổ biến nhất là kiểu kép cho phép người dùng chuyển đổi giữa hai lựa chọn – đánh dấu và bỏ đánh dấu.
Phần tử này cố gắng tự áp dụng các thuộc tính role="checkbox"
và tabindex="0"
trong lần tạo đầu tiên. Thuộc tính role
giúp công nghệ hỗ trợ như trình đọc màn hình cho người dùng biết đây là loại chế độ điều khiển nào. Thuộc tính tabindex
chọn phần tử theo thứ tự thẻ, giúp bàn phím có thể lấy tiêu điểm và hoạt động được. Để tìm hiểu thêm về hai chủ đề này, hãy xem phần ARIA có thể làm gì? và Sử dụng chỉ mục thẻ.
Khi bạn đánh dấu vào hộp, thao tác này sẽ thêm thuộc tính boolean checked
và đặt thuộc tính checked
tương ứng thành true
. Ngoài ra, phần tử này còn đặt thuộc tính aria-checked
thành "true"
hoặc "false"
, tuỳ thuộc vào trạng thái của phần tử đó. Nhấp vào hộp đánh dấu bằng chuột hoặc phím cách sẽ chuyển đổi các trạng thái đã đánh dấu này.
Hộp đánh dấu cũng hỗ trợ trạng thái disabled
. Nếu thuộc tính disabled
được đặt thành true hoặc thuộc tính disabled
được áp dụng, thì hộp đánh dấu sẽ đặt aria-disabled="true"
, xoá thuộc tính tabindex
và trả về tiêu điểm về tài liệu nếu hộp đánh dấu là activeElement
hiện tại.
Hộp đánh dấu được ghép nối với phần tử howto-label
để đảm bảo có tên dễ tiếp cận.
Tài liệu tham khảo
- Hướng dẫn: Các thành phần trên GitHub
- Mẫu hộp đánh dấu trong Phương pháp ghi nhận quyền tác giả ARIA 1.1
- ARIA có thể làm những gì?
- Sử dụng chỉ mục thẻ
Bản minh hoạ
Xem bản minh hoạ trực tiếp trên GitHub
Ví dụ về cách sử dụng
<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>
Mã
(function() {
Xác định các mã phím để giúp xử lý các sự kiện liên quan đến bàn phím.
const KEYCODE = {
SPACE: 32,
};
Việc sao chép nội dung từ một phần tử <template>
hiệu quả hơn so với sử dụng internalHTML vì nó giúp tránh phát sinh thêm chi phí phân tích cú pháp 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'];
}
Hàm khởi tạo của phần tử này sẽ chạy bất cứ khi nào một thực thể mới được tạo. Các thực thể được tạo bằng cách phân tích cú pháp HTML, gọi document.createElement('howto- {1})) hoặc gọi new HowToCheckbox() ! Hàm khởi tạo là một nơi phù hợp để tạo DOM bóng, mặc dù bạn nên tránh chạm vào bất kỳ thuộc tính nào hoặc con của DOM sáng vì chúng có thể chưa có sẵn.
constructor() {
super();
this.attachShadow({mode: 'open'});
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
connectedCallback()
sẽ kích hoạt khi phần tử được chèn vào DOM. Đây là một nơi phù hợp để đặt role
ban đầu, tabindex
, trạng thái nội bộ và cài đặt trình nghe sự kiện.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
Người dùng có thể đặt thuộc tính trên bản sao của một phần tử trước khi nguyên mẫu của phần tử đó được kết nối với lớp này. Phương thức _upgradeProperty()
sẽ kiểm tra mọi thuộc tính thực thể và chạy các thuộc tính đó thông qua các phương thức setter của lớp thích hợp. Hãy xem phần thuộc tính tải từng phần để biết thêm thông tin chi tiết.
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()
sẽ kích hoạt khi phần tử bị xóa khỏi DOM. Đây là nơi phù hợp để dọn dẹp các công việc như phát hành tệp đối chiếu và xoá trình nghe sự kiện.
disconnectedCallback() {
this.removeEventListener('keyup', this._onKeyUp);
this.removeEventListener('click', this._onClick);
}
Các thuộc tính và thuộc tính tương ứng phải phản ánh lẫn nhau. Phương thức setter thuộc tính cho đã đánh dấu xử lý các giá trị trung thực/giả và phản ánh các giá trị đó cho trạng thái của thuộc tính. Xem phần tránh truy cập lại để biết thêm chi tiết.
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()
được gọi khi bất kỳ thuộc tính nào trong mảng "{Attributes" thay đổi. Bạn nên xử lý các hiệu ứng phụ, chẳng hạn như đặt thuộc tính 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);
Thuộc tính tabindex
không đưa ra cách xoá hoàn toàn khả năng lấy tiêu điểm khỏi một phần tử. Bạn vẫn có thể lấy tiêu điểm các phần tử có tabindex=-1
bằng chuột hoặc bằng cách gọi focus()
. Để đảm bảo một phần tử bị vô hiệu hoá và không thể làm tâm điểm, hãy xoá thuộc tính tabindex
.
if (hasValue) {
this.removeAttribute('tabindex');
Nếu tiêu điểm hiện nằm trên phần tử này, hãy huỷ lấy tiêu điểm bằng cách gọi phương thức HTMLElement.blur()
this.blur();
} else {
this.setAttribute('tabindex', '0');
}
break;
}
}
_onKeyUp(event) {
Không xử lý các phím tắt đối tượng sửa đổi thường được công nghệ hỗ trợ sử dụng.
if (event.altKey)
return;
switch (event.keyCode) {
case KEYCODE.SPACE:
event.preventDefault();
this._toggleChecked();
break;
Mọi thao tác nhấn phím khác sẽ bị bỏ qua và trả về trình duyệt.
default:
return;
}
}
_onClick(event) {
this._toggleChecked();
}
_toggleChecked()
gọi phương thức setter đã đánh dấu và lật trạng thái của phương thức đó. Vì _toggleChecked()
chỉ do một hành động của người dùng gây ra, nên thao tác này cũng sẽ gửi một sự kiện thay đổi. Sự kiện này sẽ bắt chước hành vi gốc của <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);
})();