Sprawdzone metody dotyczące elementów niestandardowych

Dzięki elementom niestandardowym możesz tworzyć własne tagi HTML. Ta lista kontrolna obejmuje sprawdzone metody tworzenia elementów wysokiej jakości.

Elementy niestandardowe umożliwiają rozszerzanie kodu HTML i definiowanie własnych tagów. Są ale są też mało zaawansowane, co oznacza, że zawsze jasne, jak najlepiej wdrożyć własny element.

Aby zapewnić Ci jak najlepsze wrażenia, opracowaliśmy listę kontrolną. Ten raport zawiera wszystko, co naszym zdaniem jest potrzebne do dobrze działający element niestandardowy.

Lista kontrolna

Shadow DOM

Utwórz pierwiastek cienia, aby uwzględnić style.

Why? Umieszczając style w głównym cieniu elementu, masz pewność, że będą one działać. niezależnie od tego, gdzie są używane. Jest to szczególnie ważne, jeśli programista chce umieścić element wewnątrz rdzenia cienia innego elementu. Ten Dotyczy to nawet prostych elementów, takich jak pole wyboru czy przycisk. Może to być w przypadku gdy jedyną treścią wewnątrz cienia głównego będą style się dowiedzieć.
Przykład <howto-checkbox>.

Utwórz w konstruktorze pierwiastek cienia.

Why? Konstruktor polega na tym, że dysponujesz wyłączną wiedzą na temat elementu. To dobry moment na skonfigurowanie szczegółów implementacji, które nie powinny być bałaganów. Czynność ta zostanie wykonana podczas późniejszego wywołania zwrotnego, takiego jak connectedCallback, oznacza, że musisz zabezpieczyć się przed gdy element jest odłączony, a następnie ponownie dołączany do dokumentu.
Przykład <howto-checkbox>.

Umieść wszystkie elementy podrzędne utworzone przez element w jego rdzeniu cienia.

Why? Elementy podrzędne tworzone przez Twój element są częścią jego implementacji i powinny prywatne. Bez ochrony rdzenia cienia kod JavaScript może nieumyślnie przeszkadzały tym dzieciom.
Przykład <howto-tabs>.

Użyj <slot> aby umieścić elementy podrzędne DOM Light w modelu Shadow DOM.

Why? Jeśli zezwolisz użytkownikom komponentu na określenie treści jako elementów podrzędnych HTML, będzie on bardziej kompozycyjny. Jeśli przeglądarka nie obsługuje elementów niestandardowych, zagnieżdżona treść pozostaje dostępna, widoczna i dostępna.
Przykład <howto-tabs>.

Ustaw styl wyświetlania w polu :host (np. block, inline-block, flex), chyba że wolisz użyć domyślnej inline.

Why? Domyślna wartość elementów niestandardowych to display: inline, więc ustawienie ich width lub height nie będą miały żadnego efektu. Często jest niespodzianką dla programistów i może powodować problemy związane układając stronę. O ile nie wolisz wyświetlacza inline, zawsze powinien mieć ustawioną domyślną wartość display.
Przykład <howto-checkbox>.

Dodaj styl wyświetlania :host, który uwzględnia ukryty atrybut.

Why? Element niestandardowy z domyślnym stylem display, np. :host { display: block }, zastąpi mniejszą szczegółowość wbudowane hidden. Może to Cię zaskoczyć, jeśli spodziewasz się ustawienia atrybutu hidden w elemencie, by renderować go display: none. Dodatkowo do domyślnego stylu display, dodaj obsługę stylu hidden dzięki funkcji :host([hidden]) { display: none }.
Przykład <howto-checkbox>.

Atrybuty i właściwości

Nie zastępuj atrybutów globalnych ustawionych przez autora.

Why? Atrybuty globalne to atrybuty, które występują we wszystkich elementach HTML. Niektóre np. tabindex i role. Element niestandardowy może ustawić początkowy tabindex na 0, aby to był klawiatura które można zaznaczyć. Zawsze jednak należy najpierw sprawdzić, czy programista Twój element ustawił inną wartość. Jeśli na przykład ustawili tabindex do -1, jest to sygnał, że klient nie chce do elementu interaktywnego.
Przykład <howto-checkbox>. Szczegółowo wyjaśniliśmy to w Nie zastępuj autora strony.

Zawsze akceptuj podstawowe dane (ciągi znaków, liczby, wartości logiczne) jako dowolny atrybut lub właściwości.

Why? Elementy niestandardowe, tak jak ich wbudowane odpowiedniki, powinny dawać się konfigurować. Konfiguracja można przekazywać deklaratywnie, za pomocą atrybutów lub imperatywnie za pomocą właściwości JavaScript. Najlepiej, gdyby każdy atrybut był również powiązany z z odpowiednią usługą.
Przykład <howto-checkbox>.

Dąż do synchronizacji atrybutów i właściwości podstawowych danych, odzwierciedlając do atrybutu i odwrotnie.

Why? Nigdy nie wiadomo, jak użytkownik zareaguje na Twój element. Może ustawić właściwość w JavaScript, a następnie odczytać tę wartość za pomocą interfejsu API takiego jak getAttribute(). Jeśli każdy atrybut ma atrybut i odzwierciedlają oba te elementy, ułatwi do pracy z elementem. Innymi słowy, setAttribute('foo', value) powinien też ustawić odpowiednią wartość foo i odwrotnie. Oczywiście istnieją oczywiście wyjątki, tę regułę. Nie należy odzwierciedlać właściwości o dużej częstotliwości, np. currentTime w odtwarzaczu. Kieruj się własną oceną. Jeśli sprawia wrażenie, że użytkownik wchodzi w interakcję z właściwością lub atrybutem oraz odzwierciedlenie tego faktu nie jest męczące.
Przykład <howto-checkbox>. Szczegółowo wyjaśniliśmy to w Unikaj problemów z ponownym wyświetlaniem.

Staraj się akceptować tylko dane sformatowane (obiekty, tablice) jako właściwości.

Why? Zasadniczo nie ma przykładów wbudowanych elementów HTML, które Akceptuj dane rozszerzone (zwykłe obiekty i tablice JavaScript) za pomocą . Dane rozszerzone są akceptowane przez wywołania metody lub usług. Akceptowanie danych rozszerzonych jako zserializowanie dużego obiektu do ciągu znaków może być kosztowne, wszystkie odwołania do obiektów zostaną utracone w trakcie tego procesu wprowadzania ciągu znaków. Dla: Ciąg znaków z obiektu, który odwołuje się do innego obiektu, lub węzła DOM, odwołania te zostaną utracone.

Nie odzwierciedlaj rozszerzonych właściwości danych w atrybutach.

Why? przekształcanie szczegółowych właściwości danych w atrybuty jest niepotrzebnie kosztowne, wymaga serializacji i deserializacji tych samych obiektów JavaScript. O ile masz przypadek użycia, który da się rozwiązać tylko za pomocą tej funkcji, najlepiej będzie ich unikać.

Rozważ sprawdzenie właściwości, które mogły zostać ustawione przed elementem. uaktualniono.

Why? Programista korzystający z Twojego elementu może próbować ustawić jego właściwość. przed załadowaniem jego definicji. Dotyczy to zwłaszcza sytuacji, gdy Deweloper używa platformy, która zajmuje się wczytywaniem komponentów, oznaczaniem ich i powiąż ich właściwości z modelem.
Przykład <howto-checkbox>. Bardziej szczegółowe informacje: Ustawianie właściwości jako leniwe.

Nie zgłaszaj zajęć samodzielnie.

Why? Elementy, które muszą określać swój stan, powinny to robić za pomocą atrybutów. Uznaje się, że atrybut class należy do używając Twojego elementu i przez pomyłkę wpisanie do niego kodu iść na zajęcia z programowania.

Wydarzenia

Wysyłanie zdarzeń w odpowiedzi na działanie komponentu wewnętrznego.

Why? Komponent może mieć właściwości, które zmieniają się w odpowiedzi na działanie, tylko komponent wie o lub gdy zasób zostanie wczytany. Warto wysyłać zdarzenia w odpowiedzi na te zmiany, aby powiadomić hosta, że stan komponentu to w inny sposób.

Nie wysyłaj zdarzeń w odpowiedzi na ustawienie właściwości przez hosta (w dół przepływu danych).

Why? Wysyłanie zdarzenia w odpowiedzi na ustawienie hosta w usłudze jest niepotrzebne (gospodarz zna bieżący stan, ponieważ go ustawił). Zdarzenia wysyłania w odpowiedzi na ustawienie hosta usługa może powodować nieskończoną pętlę danych systemów wiążących.
Przykład <howto-checkbox>.

Filmy objaśniające

Nie zastępuj autora strony

Może się zdarzyć, że programista używający Twojego elementu będzie chciał zastąpić część stanie początkowym. Na przykład zmiana ARIA role lub zaznaczenia za pomocą tabindex Sprawdź, czy ustawiono te i inne atrybuty globalne. przed zastosowaniem własnych wartości.

connectedCallback() {
  if (!this.hasAttribute('role'))
    this.setAttribute('role', 'checkbox');
  if (!this.hasAttribute('tabindex'))
    this.setAttribute('tabindex', 0);

Ustaw właściwości jako leniwe

Programista może spróbować ustawić właściwość w elemencie, zanim jego definicja została wczytana. Zwłaszcza wtedy, gdy deweloper korzysta z która obsługuje wczytywanie komponentów i umieszczanie ich na stronie, ich właściwości z modelem.

W tym przykładzie Angular deklaratywnie wiąże model swojego modelu właściwość isChecked do właściwości checked pola wyboru. Jeśli definicja zapytania pole wyboru instrukcji zostało leniwie ładowane, możliwe, że Angular próbował ustawić zaznaczoną właściwość przed uaktualnieniem elementu.

<howto-checkbox [checked]="defaults.isChecked"></howto-checkbox>

W tym scenariuszu element niestandardowy powinien sprawdzać, czy jakieś właściwości mają została już ustawiona w instancji. <howto-checkbox> demonstruje ten wzorzec przy użyciu metody o nazwie _upgradeProperty().

connectedCallback() {
  ...
  this._upgradeProperty('checked');
}

_upgradeProperty(prop) {
  if (this.hasOwnProperty(prop)) {
    let value = this[prop];
    delete this[prop];
    this[prop] = value;
  }
}

_upgradeProperty() przechwytuje wartość z nieuaktualnionej instancji i usuwa właściwości, tak aby nie powielała ona metody ustawiającej właściwości elementu niestandardowego. Dzięki temu, gdy definicja elementu w końcu zostanie wczytana, może od razu będą odzwierciedlać właściwy stan.

Unikanie problemów z ponownym wyświetlaniem

Może łatwo odzwierciedlić stan w polu attributeChangedCallback() usługi bazowej, na przykład:

// When the [checked] attribute changes, set the checked property to match.
attributeChangedCallback(name, oldValue, newValue) {
  if (name === 'checked')
    this.checked = newValue;
}

Może to jednak spowodować nieskończoną pętlę, jeśli licytujący będzie też odzwierciedlić atrybut.

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');
}

Można też zezwolić na odzwierciedlenie przez narzędzie ustawiające właściwości w odniesieniu do atrybutu, deweloper określi jego wartość na podstawie atrybutu.

set checked(value) {
  const isChecked = Boolean(value);
  if (isChecked)
    this.setAttribute('checked', '');
  else
    this.removeAttribute('checked');
}

get checked() {
  return this.hasAttribute('checked');
}

W tym przykładzie dodanie lub usunięcie atrybutu spowoduje ustawienie właściwości.

attributeChangedCallback() może też służyć do obsługi efektów ubocznych. np. stosowanie stanów 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;
    ...
  }
}