Web Components: So verwendest du Code plattformübergreifend wieder

Custom Elements

Mit dem Custom-Elements-Standard könnt ihr eure eigenen HTML-Elemente definieren. Die ganze Geschichte basiert im Wesentlichen auf der Klassen-Syntax von ES6, das sieht ungefähr so aus:

class GreetingElement extends T3N {
// class definition goes here
}

Für die Custom Elements würde das Ganze so aussehen:

class GreetingElement extends HTMLElement{}

Vor den Web Components würde euer Browser jetzt einen Error ausspucken, man konnte HTMLElement nicht extenden. Euer Browser weiß, dass ein h1-Tag zur HTMLHeading1-Klasse gehört, aber woher soll er wissen, welchen Tag er einer selbstdefinierten Element-Klasse zuordnen soll? Zusätzlich den Klassen der nativen HTML-Elemente gibt es extra dafür ein „Custom Element Register“, euer Element könnt ihr so hinzufügen:

customElements.define(‘greeting-element‘, GreetingElement);

So stellt ihr sicher, dass der Browser jeden geparsten t3ns-element-Tag mit einer neuen Instanz von GreetingElement assoziiert. Übrigens: Eure Custom Elements müssen einen Bindestrich enthalten, um sie in der Benennung von den nativen HTML-Elementen abzugrenzen. Vergesst also am besten die Idee, eine h7 zu machen – das geht nicht. Außer, dass der Constructor jedes Mal, wenn euer Custom Element gerendert werden soll, aufgerufen wird, gibt es noch eine Reihe zusätzlicher Lifecycle-Methoden:

  • connectedCallback – wird aufgerufen, wenn ein Element an ein Dokument angefügt wird. Das kann öfter als ein Mal vorkommen, zum Beispiel, wenn es bewegt oder entfernt und wieder hinzugefügt wird.
  • disconnectedCallback – ist das Gegenstück zu connectedCallback.
  • attributeChangeCallback – feuert immer dann, wenn sich Attribute ändern.

Custom-Elements-Demo. (Bild: Codepen)

Würdet ihr das Element auf einer Seite nutzen wollen, sähe das so aus:

Custom-Elements-Demo (Bild: Codepen)

Und native HTML-Elemente?

Wollt ihr ein natives HTML-Element extenden, sieht das Markup etwas anders aus. Wenn ihr zum Beispiel wollt, dass euer GreetingElement ein Button ist, würde das so aussehen:

class GreetingElement extends HTMLButtonElement

Dann müsst ihr noch festlegen, dass es sich hierbei um ein natives Element handelt, das geht so:

customElements.define('hello-there', GreetingElement, { extends: 'button' });

Custom-Elements-Demo (Bild: Codepen)

Weil es sich um ein natives HTML-Element handelt, nutzt ihr an dieser Stelle den button-Tag anstelle eures Custom-Tags. Außerdem braucht ihr das is-Attribut, sonst weiß der Browser nicht, dass euer Custom-Element eine Art Button ist.

Klingt vielleicht erstmal kompliziert, muss aber so. Auch assistive Technologien orientieren sich zum Beispiel an diesem Markup. Jetzt könnt ihr Styling und EventHandler hinzufügen oder das Ganze in template-Tags wrappen, wenn ihr wollt. Andere können euer Custom Element in ihrem eigenen Code verwenden – über HTML-Templating, DOM-Calls und sogar ziemlich problemlos in bekannten Frameworks wie zum Beispiel AngularJS.

Zusammengefasst bringen die Custom Elements folgende Vorteile:

  • Die Möglichkeit, die HTMLElement-Klasse und ihre Unterklassen zu extenden.
  • Ein Register für die Custom Elements – über customElements.define() werden CustomElements dort abgelegt.
  • Eigene Lifecycle-Callbacks, über die ihr zum Beispiel Attributveränderungen, Element-Bildung und das Hinzufügen zum DOM verfolgen könnt.

Shadow DOM

Die Besonderheit an euren Custom Elements ist, dass ihr sie auch in anderen Anwendungen wiederverwenden wollt und eigentlich auch andere Entwickler sie wiederverwenden können sollen. Den Shadow DOM gibt es, um Konflikte zwischen Custom Element und CSS anderer Websites oder Apps zu umgehen.

Alle Elemente und Styles innerhalb eines HTML-Dokuments und innerhalb des DOM befinden sich in einem globalen Scope. Auf jedes Element auf einer Seite könnt ihr über document.querySelector() zugreifen und auf das Dokument angewandte CSS-Styles können jedes Element auswählen, egal, wo es sich befindet. Das ist cool, wenn ihr Styles auf das gesamte Dokument anwenden wollt – zum Beispiel, um an alle Elemente das gleiche box-sizing zu vergeben.

Manchmal ist das aber auch nicht cool. Manchmal braucht ihr Elemente, die nicht von globalen Styles betroffen sind, wie zum Beispiel ein Third-Party-Widget wie der Teilen-Button für Facebook oder ein Follow-Button für Twitter.  Über die Verwendung eines iframe kann sichergestellt werden, dass das Widget nicht vom CSS des Dokuments behelligt wird, in das ihr es einbinden wollt.

Genau an dieser Stelle kommt das Shadow DOM ins Spiel. Das Shadow DOM ist quasi ein DOM innerhalb des DOM – ein eigenes DOM mit eigenen Elementen und Styles, komplett unabhängig vom DOM eures Dokuments. Das Shadow DOM liegt auch Form-Elementen wie zum Beispiel dem range-input-Element oder auch Radio-Buttons zugrunde: Für ein range-input müsst ihr zum Beispiel einfach input type=“range“schreiben und bekommt dann einen Slider. Das input-Element selbst besteht allerdings aus mehreren kleineren divs, über die Track und Slider kontrolliert werden. Euer Dokument und alles, was sich darin befindet, kann nur das input-Element sehen, nicht die Elemente und Styles, die für Aussehen und Funktionalität sorgen. Erreicht wird das über den Shadow DOM.

Und wie funktioniert das Ganze konkret?

Um zu illustrieren, wie der Shadow DOM funktioniert, bauen wir einen Twitter-Button – ohne iframe – mit dem Shadow DOM. Dafür braucht ihr zuerst den Shadow Host – das native HTML-Element innerhalb des globalen DOM, an das wir unseren Shadow DOM anhängen wollen.

Shadow-DOM-Demo. (Bild: Codepen)

Im Beispiel hängen wir den Shadow DOM an ein span. Den Shadow DOM einfach an den Link zu hängen, was das Naheliegende wäre, funktioniert nicht, weil manche HTML-Elemente kein Shadow Host sein dürfen. Diese Restriktion betrifft vor allem interaktive Elemente. Um den Shadow DOM an den span anzuhängen, nutzen wir die attachShadow()-Methode.

const shadowEl = document.querySelector(".shadow-host");
const shadow = shadowEl.attachShadow({mode: 'open'});

So entsteht eine leere Shadow Root, die das Kindelement des Shadow Host ist. Die Shadow Root ist quasi der Anfang des Shadow DOM, so wie das html-Element der Beginn des regulären DOM ist. Dann wollen wir unseren Shadow-Komponentenbaum ausbauen. Der Shadow-Tree ist genau wie ein DOM-Tree, nur für das Shadow-DOM. Für einen Twitter-Button braucht ihr nur ein neues <a>-Element – eigentlich genau wie der Link im vorherigen Beispiel. Stylen könnt ihr den Button, indem ihr ein Style-Element erstellt, die gewünschten Styles definiert und es dann über die appendChild()-Methode dem Shadow DOM hinzufügt. Das gesamte Beispiel findet ihr bei Codepen.io.

Kombiniert ihr die Standards, sieht der Workflow für die Erstellung und Verwendung der Web Components ungefähr so aus:

  1. Ihr erstellt eine JavaScript-Klasse (oder -Funktion), in der ihr die Funktionalität eurer Web Component spezifiziert.
  2. Ihr registriert euer neues Custom Element über die CustomElementRegistry.define() -Methode, definiert das name-Attribut und die Klasse oder Funktion, die seine Funktionalität spezifiziert und optional, von welchem Element es vererbt.
  3. Falls benötigt, fügt ihr mit der Element.attachShadow()-Methode einen Shadow DOM an euer Custom Element an. Kind-Elemente, Event-Listener und alles weitere fügt ihr wie gehabt mit regulären DOM-Methoden hinzu.
  4. Anschließend könnt ihr ein HTML-Temlate mittels <template> und <slot> definieren, wenn ihr wollt. Zum Klonen des Templates verwendet ihr, wie in Beispiel 4 ersichtlich, reguläre DOM-Methoden.
  5. Jetzt lässt sich euer Custom Element verwenden wie jedes reguläre HTML-Element, für euch und für alle anderen, die Verwendung dafür finden.

Weitere detaillierte Tutorials und Definitionen findet ihr zum Beispiel bei MDN oder in den Web Fundamentals Guidelines von Google.

weiterlesen auf t3n.de
Source: Cloudnachrichtem

Tags:

Keine Kommentare

    Hinterlasse einen Kommentar

    error: sorry..