Best Practices für benutzerdefinierte Elemente

Mit benutzerdefinierten Elementen können Sie Ihre eigenen HTML-Tags erstellen. Diese Checkliste enthält Best Practices für die Erstellung qualitativ hochwertiger Elemente.

Mit benutzerdefinierten Elementen können Sie HTML erweitern und eigene Tags definieren. Sie sind ein ist eine leistungsstarke Funktion, die aber nicht besonders schlecht ist. immer klar sein, wie Sie Ihr eigenes Element am besten implementieren.

Um Ihnen die bestmögliche Erfahrung zu bieten, haben wir Checkliste. Sie schlüsselt all die Dinge auf, die wir für gut funktioniertes benutzerdefiniertes Element.

Erstellen Sie einen Schattenstamm, um Stile zu kapseln.

Warum? Durch die Kapselung von Stilen im Schattenstamm Ihres Elements wird sichergestellt, dass es funktioniert. unabhängig davon, wo sie verwendet werden. Das ist besonders wichtig, Ihr Element innerhalb des Schattenstamms eines anderen Elements platzieren möchte. Dieses gilt auch für einfache Elemente wie Kästchen oder Optionsfelder. Möglicherweise Der einzige Inhalt innerhalb des Schattenstamms sind die Stile selbst.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Erstellen Sie den Schattenstamm im Konstruktor.

Warum? Für den Konstruktor haben Sie exklusive Kenntnisse Ihres Elements. Jetzt sollten Sie Details zur Implementierung festlegen, die Sie nicht Elemente, die das Problem verursachen. Dies geschieht in einem späteren Callback wie dem connectedCallback bedeutet, dass Sie vor in denen Ihr Element getrennt und dann wieder an das Dokument angehängt wird.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Platzieren Sie alle untergeordneten Elemente, die vom Element erstellt werden, in den Schattenstamm.

Warum? Von Ihrem Element erstellte untergeordnete Elemente sind Teil seiner Implementierung und sollten privat. Ohne den Schutz eines Schattenstamms können externe JavaScript-Dateien die diese Kinder unbeabsichtigt stören könnten.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-tabs>-Element.

<slot> verwenden um Light-DOM-Child in Ihr Shadow DOM zu projizieren

Warum? Ermöglichen Sie Nutzern Ihrer Komponente, Inhalte in Ihrer Komponente anzugeben, da durch untergeordnete HTML-Elemente Ihre Komponente besser zusammensetzbar ist. Wenn ein Browser keine benutzerdefinierten Elemente unterstützt, bleibt der verschachtelte Inhalt verfügbar, sichtbar und zugänglich.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-tabs>-Element.

Anzeigestil für :host festlegen (z.B. block, inline-block, flex), es sei denn, Sie bevorzugen die Standardeinstellung inline

Warum? Benutzerdefinierte Elemente sind standardmäßig auf display: inline gesetzt. width oder height haben keine Auswirkungen. So oft für Entwickler überrascht und zu Problemen in Bezug auf Layout der Seite. Sofern Sie kein inline-Display bevorzugen, sollte immer einen Standardwert für display festlegen.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Fügen Sie einen :host-Anzeigestil hinzu, der das ausgeblendete Attribut berücksichtigt.

Warum? Ein benutzerdefiniertes Element mit einem Standardformat für display, z.B. :host { display: block }, überschreibt die niedrigere Spezifität integriert <ph type="x-smartling-placeholder"></ph> hidden-Attribut. Dies könnte Sie überraschen, wenn Sie das Festlegen des hidden erwarten. auf Ihrem Element, um es display: none zu rendern. Außerdem auf einen display-Standardstil angewendet, jetzt Unterstützung für hidden hinzufügen mit :host([hidden]) { display: none }.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Attribute und Eigenschaften

Überschreiben Sie keine globalen Attribute vom Typ "author-set".

Warum? Globale Attribute sind Attribute, die in allen HTML-Elementen vorhanden sind. Einige Beispiele sind tabindex und role. Ein benutzerdefiniertes Element kann die anfängliche tabindex auf 0 setzen, damit sie über die Tastatur erfolgt. fokussierbar. Sie sollten jedoch immer zuerst prüfen, ob der Entwickler Ihr Element hat dies auf einen anderen Wert gesetzt. Wenn zum Beispiel tabindex bis -1 ist das ein Signal dafür, dass das -Elements interaktiv sein.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element. Dies wird unter Überschreiben Sie nicht den Seitenautor.

Primitive Daten (Strings, Zahlen, boolesche Werte) immer als Attribute akzeptieren oder Eigenschaften.

Warum? Benutzerdefinierte Elemente sollten wie ihre integrierten Entsprechungen konfigurierbar sein. Die Konfiguration kann deklarativ, über Attribute oder imperativ übergeben werden. über JavaScript-Eigenschaften. Idealerweise sollte jedes Attribut auch mit eine entsprechende Property.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Versuchen Sie, primitive Datenattribute und Eigenschaften synchron zu halten, und umgekehrt.

Warum? Sie wissen nie, wie Nutzende mit Ihrem Element interagieren werden. Sie könnten eine Eigenschaft in JavaScript festlegen und dann erwarten, mit einer API wie getAttribute(). Wenn jedes Attribut und beide reflektieren, können Nutzer mit Ihrem Element zu arbeiten. Mit anderen Worten: Das Aufrufen setAttribute('foo', value) sollte auch eine entsprechende foo und umgekehrt. Natürlich gibt es Ausnahmen für für diese Regel. Sie sollten keine Eigenschaften mit hoher Häufigkeit reflektieren, z.B. currentTime in einem Videoplayer. Entscheiden Sie selbst. Wenn es Es scheint, als würde ein Nutzer mit einer Property oder einem Attribut interagieren. ist es nicht schwer, das zu reflektieren.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element. Dies wird unter Rücknahmeprobleme vermeiden:

Versuchen Sie, nur Rich-Daten (Objekte, Arrays) als Eigenschaften zu akzeptieren.

Warum? Im Allgemeinen gibt es keine Beispiele für integrierte HTML-Elemente, die Rich-Daten (einfache JavaScript-Objekte und Arrays) über ihre Attribute. Rich-Daten werden stattdessen entweder über Methodenaufrufe oder Eigenschaften. Es gibt einige offensichtliche Nachteile, Die Serialisierung eines großen Objekts in einem String kann teuer sein. Dabei gehen alle Objektverweise verloren. Für Wenn Sie z. B. ein Objekt als String angeben, das einen Verweis auf ein anderes Objekt hat, oder vielleicht auf einen DOM-Knoten, gehen diese Bezüge verloren.

Rich-Daten-Eigenschaften für Attribute nicht darstellen.

Warum? Das Abbilden umfangreicher Dateneigenschaften in Attribute ist unnötig teuer. die Serialisierung und Deserialisierung derselben JavaScript-Objekte erfordern. Es sei denn, gibt es einen Anwendungsfall, der nur mit dieser Funktion gelöst werden kann, ist es wahrscheinlich, vermeiden sollten.

Prüfen Sie, ob Eigenschaften vorhanden sind, die möglicherweise vor dem Element festgelegt wurden. aktualisiert.

Warum? Ein Entwickler, der Ihr Element verwendet, kann versuchen, eine Eigenschaft für das Element festzulegen bevor die Definition geladen wurde. Dies gilt insbesondere, wenn das das Laden von Komponenten übernimmt, mit der Seite verknüpft und ihre Properties an ein Modell gebunden.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element. Weitere Erläuterungen finden Sie unter Machen Sie Properties faul.

Wenden Sie die Kurse nicht selbst an.

Warum? Elemente, die ihren Status ausdrücken müssen, sollten dies mithilfe von Attributen tun. Die wird im Allgemeinen davon ausgegangen, dass das Attribut class dem und selbst etwas schreiben kann, und Entwicklerkursen.

Ereignisse

Löst Ereignisse als Reaktion auf interne Komponentenaktivitäten aus.

Warum? Ihre Komponente kann Eigenschaften aufweisen, die sich als Reaktion auf Aktivitäten ändern, die nur Ihre Komponente weiß, beispielsweise ob ein Timer oder eine Animation oder eine Ressource vollständig geladen ist. Es ist hilfreich, Ereignisse um den Host zu informieren, dass der Status der Komponente unterscheiden.

Keine Ereignisse auslösen, wenn der Host ein Attribut festlegt (abwärts Datenfluss).

Warum? Das Auslösen eines Ereignisses als Reaktion auf die Festlegung einer Eigenschaft durch den Host ist überflüssig (Der Host kennt den aktuellen Status, da er ihn gerade festgelegt hat.) Ereignisse auslösen Als Reaktion auf eine Hosteinstellung kann eine Eigenschaft Endlosschleifen mit Daten verursachen Bindungssysteme.
Beispiel Die <ph type="x-smartling-placeholder"></ph> <howto-checkbox>-Element.

Erklärvideos

Seitenautor nicht überschreiben

Es ist möglich, dass ein Entwickler, der Ihr Element verwendet, einige in den Ausgangszustand versetzt. Ändern der ARIA-role oder der Fokussierbarkeit mit tabindex. Überprüfen Sie, ob diese und andere globale Attribute festgelegt wurden. bevor Sie Ihre eigenen Werte anwenden.

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

Eigenschaften faul machen

Ein Entwickler könnte versuchen, eine Eigenschaft für ein Element festzulegen, bevor Definition wurde geladen. Dies gilt insbesondere, wenn der Entwickler Framework, das das Laden von Komponenten, das Einfügen dieser Komponenten auf die Seite Bindung ihrer Attribute an ein Modell.

Im folgenden Beispiel bindet Angular die Funktion isChecked zur checked-Eigenschaft des Kästchens hinzu. Wenn die Definition für wenn ein Lazy Loading für die Anleitung aktiviert war. die ausgewählte Eigenschaft ein, bevor das Element aktualisiert wurde.

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

Ein benutzerdefiniertes Element sollte für dieses Szenario geeignet sein, indem geprüft wird, ob Eigenschaften für die Instanz festgelegt ist. Die <howto-checkbox> veranschaulicht dieses Muster mithilfe der Methode _upgradeProperty().

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

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

_upgradeProperty() erfasst den Wert aus der nicht aktualisierten Instanz und löscht der Eigenschaft fest, damit sie den eigenen Eigenschaften-Setter des benutzerdefinierten Elements nicht verdeckt. Wenn die Definition des Elements schließlich geladen wird, kann sie den richtigen Zustand widerspiegelt.

Rücknahmeprobleme vermeiden

Es ist verlockend, den attributeChangedCallback() zu verwenden, um den Zustand zugrunde liegende Property. Beispiel:

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

Dies kann jedoch eine Endlosschleife erzeugen, wenn der Eigenschafts-Setter auch das Attribut.

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

Alternativ können Sie zulassen, dass der Property-Setter das Attribut reflektiert. Sie lassen den Getter seinen Wert anhand des Attributs bestimmen.

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

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

In diesem Beispiel wird durch das Hinzufügen oder Entfernen des Attributs auch die Eigenschaft festgelegt.

Schließlich können mit attributeChangedCallback() Nebenwirkungen verarbeitet werden. wie das Anwenden von ARIA-Zuständen.

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;
    ...
  }
}