Các phần tử tuỳ chỉnh cho phép bạn tạo thẻ HTML của riêng mình. Danh sách kiểm tra này bao gồm các phương pháp hay nhất để giúp bạn tạo các phần tử chất lượng cao.
Các phần tử tuỳ chỉnh cho phép bạn mở rộng HTML và xác định các thẻ của riêng bạn. Họ là
đây là một tính năng vô cùng mạnh mẽ nhưng cũng ở cấp độ thấp, có nghĩa là
luôn rõ ràng cách tốt nhất để triển khai yếu tố của riêng bạn.
Để giúp bạn tạo ra trải nghiệm tốt nhất có thể, chúng tôi đã tổng hợp
danh sách kiểm tra. Công cụ này chia nhỏ tất cả những yếu tố mà chúng tôi cho rằng cần có để trở thành một
hoạt động tốt.
Danh sách kiểm tra
DOM bóng
Tạo gốc đổ bóng để đóng gói các kiểu. |
Tại sao? |
Việc đóng gói các kiểu trong gốc đổ bóng của phần tử đảm bảo rằng kiểu đó sẽ hoạt động
bất kể nó được sử dụng ở đâu. Điều này đặc biệt quan trọng nếu nhà phát triển
muốn đặt phần tử của bạn bên trong gốc bóng của một phần tử khác. Chiến dịch này
áp dụng cho cả các phần tử đơn giản như hộp đánh dấu hoặc nút chọn. Có thể là
trong trường hợp nội dung duy nhất bên trong thư mục gốc của bóng sẽ là kiểu
chính họ.
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Tạo gốc đổ bóng trong hàm khởi tạo.
|
Tại sao? |
Hàm khởi tạo là khi bạn có Kiến thức độc quyền về phần tử của mình.
Đây là thời điểm tuyệt vời để thiết lập các chi tiết triển khai mà bạn không muốn
không có nhiều yếu tố. Thực hiện công việc này trong lệnh gọi lại sau đó, chẳng hạn như
connectedCallback , nghĩa là bạn cần đề phòng
trong trường hợp phần tử của bạn bị tách rời và sau đó được đính kèm lại vào tài liệu.
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Đặt mọi phần tử con mà phần tử tạo ra vào gốc bóng của nó.
|
Tại sao? |
Phần tử con do phần tử của bạn tạo là một phần trong quá trình triển khai và nên được
riêng tư. Nếu không có sự bảo vệ của gốc bóng, JavaScript bên ngoài có thể
vô tình can thiệp vào những trẻ em này.
|
Ví dụ |
Phần tử <howto-tabs> .
|
Sử dụng <slot> để chiếu các phần tử con DOM sáng vào DOM tối của bạn
|
Tại sao? |
Cho phép người dùng trong thành phần của bạn chỉ định nội dung trong thành phần vì thành phần con HTML sẽ giúp thành phần đó trở nên dễ kết hợp hơn. Khi trình duyệt không hỗ trợ các phần tử tuỳ chỉnh, nội dung lồng nhau vẫn có sẵn, hiển thị và truy cập được.
|
Ví dụ |
Phần tử <howto-tabs> .
|
Đặt kiểu hiển thị :host (ví dụ: block ,
inline-block , flex ) trừ phi bạn thích giá trị mặc định là
inline .
|
Tại sao? |
Các phần tử tuỳ chỉnh là display: inline theo mặc định, vì vậy, việc đặt phần tử
width hoặc height sẽ không có hiệu lực. Tần suất này
làm nhà phát triển ngạc nhiên và có thể gây ra các vấn đề liên quan đến
bố trí trang. Nếu không muốn dùng màn hình inline , bạn có thể
phải luôn đặt giá trị display mặc định.
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Thêm kiểu hiển thị :host tuân theo thuộc tính ẩn.
|
Tại sao? |
Một phần tử tuỳ chỉnh có kiểu display mặc định, ví dụ:
:host { display: block } , sẽ thay thế độ đặc hiệu thấp hơn
tích hợp sẵn
thuộc tính hidden .
Bạn có thể ngạc nhiên nếu muốn đặt hidden
trên phần tử của bạn để hiển thị nó display: none . Ngoài ra
thành kiểu display mặc định, hãy thêm tính năng hỗ trợ cho hidden
cùng với :host([hidden]) { display: none } .
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Thuộc tính và thuộc tính
Không ghi đè các thuộc tính chung, do nhóm tác giả thiết lập.
|
Tại sao? |
Thuộc tính chung là những thuộc tính có trên tất cả các phần tử HTML. Hơi nhiều
Ví dụ: tabindex và role . Phần tử tuỳ chỉnh
có thể cần đặt tabindex ban đầu thành 0 để thiết bị này trở thành bàn phím
có thể làm tâm điểm. Nhưng bạn phải luôn kiểm tra trước để xem liệu nhà phát triển đang sử dụng
phần tử của bạn đã đặt giá trị này thành một giá trị khác. Ví dụ: nếu họ đặt
tabindex thành -1, đó là tín hiệu cho thấy họ không muốn
tương tác.
|
Ví dụ |
Phần tử <howto-checkbox> . Điều này được giải thích thêm trong
Đừng ghi đè tác giả trang.
|
Luôn chấp nhận dữ liệu gốc (chuỗi, số, boolean) làm thuộc tính
hoặc thuộc tính.
|
Tại sao? |
Bạn nên định cấu hình các phần tử tuỳ chỉnh (như các phần tử tương đương được tích hợp sẵn).
Cấu hình có thể được chuyển vào theo cách khai báo, thông qua các thuộc tính hoặc bắt buộc
thông qua các thuộc tính JavaScript. Tốt nhất là bạn cũng nên liên kết mọi thuộc tính với
một thuộc tính tương ứng.
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Cố gắng đồng bộ hoá các thuộc tính và thuộc tính của dữ liệu gốc, phản ánh từ
vào thuộc tính đó và ngược lại.
|
Tại sao? |
Bạn không bao giờ biết cách người dùng sẽ tương tác với phần tử của mình. Chúng có thể
đặt một thuộc tính trong JavaScript, sau đó yêu cầu đọc giá trị đó
bằng cách sử dụng một API như getAttribute() . Nếu mỗi thuộc tính có một
thuộc tính tương ứng và cả hai đều phản ánh, điều này sẽ giúp
để người dùng làm việc với phần tử của bạn. Nói cách khác, việc gọi điện
setAttribute('foo', value) cũng phải đặt giá trị tương ứng
thuộc tính foo và ngược lại. Tất nhiên, vẫn có những trường hợp ngoại lệ đối với
quy tắc này. Bạn không nên phản ánh các thuộc tính tần suất cao, ví dụ:
currentTime trong trình phát video. Hãy suy xét thật kỹ lưỡng. Nếu
có vẻ như người dùng sẽ tương tác với một thuộc tính hoặc thuộc tính và
việc phản ánh điều đó không hề khó chịu, rồi bạn hãy làm như vậy.
|
Ví dụ |
Phần tử <howto-checkbox> . Điều này được giải thích thêm trong
Tránh các vấn đề về tỷ lệ người dùng quay lại.
|
Cố gắng chỉ chấp nhận dữ liệu đa dạng thức (đối tượng, mảng) làm thuộc tính.
|
Tại sao? |
Nói chung, không có ví dụ nào về các phần tử HTML tích hợp sẵn
chấp nhận dữ liệu đa dạng thức (đối tượng và mảng JavaScript thuần tuý) thông qua
. Dữ liệu đa dạng thức được chấp nhận thông qua lệnh gọi phương thức hoặc
các thuộc tính. Có một vài nhược điểm rõ ràng khi chấp nhận dữ liệu đa dạng thức như
thuộc tính: có thể tốn kém khi chuyển đổi tuần tự một đối tượng lớn thành một chuỗi và
mọi tham chiếu đối tượng đều sẽ bị mất trong quá trình chuỗi này. Cho
ví dụ: nếu bạn xâu chuỗi một đối tượng có tham chiếu đến một đối tượng khác,
hoặc có thể là nút DOM, các tham chiếu đó sẽ bị mất.
|
Đừng phản ánh các thuộc tính dữ liệu đa dạng thức vào các thuộc tính.
|
Tại sao? |
Việc phản ánh các thuộc tính dữ liệu đa dạng thức cho các thuộc tính là không cần thiết,
yêu cầu chuyển đổi tuần tự và giải tuần tự các đối tượng JavaScript giống nhau. Trừ phi
bạn có một trường hợp sử dụng chỉ có thể giải quyết bằng tính năng này,
tốt nhất là nên tránh việc đó.
|
Cân nhắc kiểm tra các thuộc tính có thể đã được đặt trước phần tử này
đã nâng cấp.
|
Tại sao? |
Nhà phát triển sử dụng phần tử của bạn có thể tìm cách đặt thuộc tính trên phần tử đó
trước khi tải định nghĩa. Điều này đặc biệt đúng nếu
nhà phát triển đang sử dụng một khung xử lý quá trình tải, đóng dấu các thành phần đó
với trang rồi liên kết các thuộc tính của chúng với một mô hình.
|
Ví dụ |
Phần tử <howto-checkbox> . Giải thích thêm trong
Đặt các thuộc tính thành lazy.
|
Không được tự áp dụng lớp học.
|
Tại sao? |
Các phần tử cần thể hiện trạng thái phải sử dụng các thuộc tính. Chiến lược phát hành đĩa đơn
Thuộc tính class thường được coi là thuộc sở hữu của
nhà phát triển đang sử dụng phần tử của bạn và tự bạn viết vào phần tử đó có thể vô tình
dậm chân vào các lớp học lập trình.
|
Sự kiện
Điều phối các sự kiện để phản hồi hoạt động của thành phần nội bộ.
|
Tại sao? |
Thành phần của bạn có thể có các thuộc tính thay đổi để phản hồi hoạt động
chỉ thành phần của bạn biết (chẳng hạn như bộ tính giờ hay ảnh động)
hoàn tất hoặc tài nguyên tải xong. Sẽ hữu ích khi điều phối các sự kiện
để phản hồi những thay đổi này nhằm thông báo cho máy chủ lưu trữ rằng trạng thái của thành phần là
khác.
|
Không gửi các sự kiện để phản hồi chế độ cài đặt của máy chủ lưu trữ (giảm dần)
luồng dữ liệu).
|
Tại sao? |
Việc điều phối một sự kiện để phản hồi chế độ cài đặt của người tổ chức sự kiện là không cần thiết
(máy chủ lưu trữ biết trạng thái hiện tại vì chỉ cần đặt trạng thái đó). Sự kiện điều phối
khi phản hồi chế độ cài đặt của máy chủ lưu trữ, một thuộc tính có thể tạo ra vòng lặp vô hạn với dữ liệu
hệ thống liên kết.
|
Ví dụ |
Phần tử <howto-checkbox> .
|
Video giải thích
Không ghi đè tác giả trang
Có thể nhà phát triển đang sử dụng phần tử của bạn muốn ghi đè một số
trạng thái ban đầu của nó. Ví dụ: thay đổi role
ARIA hoặc khả năng lấy tiêu điểm bằng
tabindex
Kiểm tra xem các thuộc tính này và bất kỳ thuộc tính chung nào khác đã được thiết lập hay chưa,
trước khi áp dụng các giá trị của riêng bạn.
connectedCallback() {
if (!this.hasAttribute('role'))
this.setAttribute('role', 'checkbox');
if (!this.hasAttribute('tabindex'))
this.setAttribute('tabindex', 0);
Đặt thành lazy cho các thuộc tính
Nhà phát triển có thể tìm cách đặt một thuộc tính trên phần tử của bạn trước
đã tải định nghĩa. Điều này đặc biệt đúng nếu nhà phát triển đang sử dụng
khung xử lý việc tải các thành phần, chèn chúng vào trang và
liên kết các thuộc tính của chúng với một mô hình.
Trong ví dụ sau, Angular được tuyên bố liên kết với mô hình của nó
isChecked
với thuộc tính checked
của hộp đánh dấu. Nếu định nghĩa cho
hộp kiểm howto-checkbox được tải từng phần, có thể Angular có thể tìm cách thiết lập
thuộc tính được đánh dấu trước khi phần tử được nâng cấp.
<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>
Một phần tử tuỳ chỉnh nên xử lý trường hợp này bằng cách kiểm tra xem có cơ sở lưu trú nào
đã được đặt trên thực thể của nó. <howto-checkbox>
minh hoạ mẫu này bằng phương thức có tên là _upgradeProperty()
.
connectedCallback() {
...
this._upgradeProperty('checked');
}
_upgradeProperty(prop) {
if (this.hasOwnProperty(prop)) {
let value = this[prop];
delete this[prop];
this[prop] = value;
}
}
_upgradeProperty()
ghi lại giá trị từ phiên bản chưa nâng cấp và xoá
thuộc tính đó để nó không làm ẩn phương thức setter thuộc tính của riêng phần tử tuỳ chỉnh.
Bằng cách này, khi định nghĩa của phần tử cuối cùng đã tải, nó có thể ngay lập tức
để phản ánh chính xác trạng thái.
Tránh các vấn đề về tỷ lệ người dùng quay lại
Bạn nên sử dụng attributeChangedCallback()
để phản ánh trạng thái cho một
thuộc tính cơ bản, ví dụ:
// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
if (name === 'checked')
this.checked = newValue;
}
Nhưng điều này có thể tạo ra một vòng lặp vô hạn nếu phương thức setter thuộc tính cũng phản ánh
thuộc tính đó.
set checked(value) {
const isChecked = Boolean(value);
if (isChecked)
// OOPS! This will cause an infinite loop because it triggers the
// attributeChangedCallback() which then sets this property again.
this.setAttribute('checked', '');
else
this.removeAttribute('checked');
}
Một cách khác là cho phép phương thức setter thuộc tính phản ánh đến thuộc tính và
để phương thức getter xác định giá trị dựa trên thuộc tính.
set checked(value) {
const isChecked = Boolean(value);
if (isChecked)
this.setAttribute('checked', '');
else
this.removeAttribute('checked');
}
get checked() {
return this.hasAttribute('checked');
}
Trong ví dụ này, việc thêm hoặc xoá thuộc tính cũng sẽ đặt thuộc tính đó.
Cuối cùng, bạn có thể dùng attributeChangedCallback()
để xử lý các hiệu ứng phụ
như áp dụng các trạng thái ARIA.
attributeChangedCallback(name, oldValue, newValue) {
const hasValue = newValue !== null;
switch (name) {
case 'checked':
// Note the attributeChangedCallback is only handling the *side effects*
// of setting the attribute.
this.setAttribute('aria-checked', hasValue);
break;
...
}
}