Die Front-End-Entwicklung bewegt sich in einem rasanten Tempo. Dies zeigt sich in den unzähligen Artikeln, Tutorials und Twitter-Threads, die den Zustand dessen beklagen, was einst ein ziemlich einfacher Technologie-Stack war. In diesem Artikel werde ich erörtern, warum Web Components ein großartiges Werkzeug sind, um hochwertige Benutzererlebnisse zu liefern, ohne komplizierte Frameworks oder Build-Schritte und ohne das Risiko, obsolet zu werden. In nachfolgenden Artikeln dieser fünfteiligen Serie werden wir tiefer in jede der Spezifikationen eintauchen.
Diese Serie setzt grundlegende Kenntnisse in HTML, CSS und JavaScript voraus. Wenn Sie sich in einem dieser Bereiche schwach fühlen, machen Sie sich keine Sorgen, denn die Erstellung eines benutzerdefinierten Elements vereinfacht viele Komplexitäten in der Front-End-Entwicklung.
Artikelserie
- Eine Einführung in Web Components (Dieser Beitrag)
- Erstellung wiederverwendbarer HTML-Vorlagen
- Creating a Custom Element from Scratch
- Kapselung von Stil und Struktur mit Shadow DOM
- Fortgeschrittene Werkzeuge für Web Components
Was sind Web Components eigentlich?
Web Components bestehen aus drei separaten Technologien, die zusammen verwendet werden
- Benutzerdefinierte Elemente. Ganz einfach gesagt, dies sind voll gültige HTML-Elemente mit benutzerdefinierten Vorlagen, Verhaltensweisen und Tag-Namen (z. B.
<one-dialog>), die mit einer Reihe von JavaScript-APIs erstellt wurden. Benutzerdefinierte Elemente sind in der HTML Living Standard Spezifikation definiert. - Shadow DOM. Fähig zur Isolierung von CSS und JavaScript, fast wie ein
<iframe>. Dies ist in der Living Standard DOM Spezifikation definiert. - HTML-Vorlagen. Vom Benutzer definierte Vorlagen in HTML, die erst gerendert werden, wenn sie aufgerufen werden. Das
<template>-Tag ist in der HTML Living Standard Spezifikation definiert.
Dies sind die Bestandteile der Web Components Spezifikation.
HTML-Module sind wahrscheinlich die vierte Technologie im Stack, aber sie wurde noch in keinem der großen vier Browser implementiert. Das Chrome-Team hat dazu eine Absicht zur Implementierung in einer zukünftigen Version angekündigt.
Web Components sind in allen wichtigen Browsern mit Ausnahme von Microsoft Edge und Internet Explorer 11 generell verfügbar, aber Polyfills existieren, um diese Lücken zu schließen.
Die Bezeichnung einer dieser Technologien als Web Components ist technisch korrekt, da der Begriff selbst etwas überladen ist. Infolgedessen können jede der Technologien unabhängig oder in Kombination mit anderen verwendet werden. Mit anderen Worten, sie sind nicht gegenseitig ausschließend.
Werfen wir einen *kurzen* Blick auf die ersten drei. In anderen Artikeln dieser Serie werden wir uns eingehender mit ihnen beschäftigen.
Benutzerdefinierte Elemente
Wie der Name schon sagt, sind benutzerdefinierte Elemente HTML-Elemente, wie <div>, <section> oder <article>, aber etwas, das wir selbst benennen können und das über eine Browser-API definiert wird. Benutzerdefinierte Elemente sind genau wie diese Standard-HTML-Elemente – Namen in spitzen Klammern – nur dass sie *immer* einen Bindestrich enthalten, wie <news-slider> oder <bacon-cheeseburger>. Zukünftig haben sich die Browserhersteller verpflichtet, keine neuen integrierten Elemente mit einem Bindestrich in ihren Namen zu erstellen, um Konflikte zu vermeiden.
Benutzerdefinierte Elemente enthalten ihre eigene Semantik, ihr eigenes Verhalten, ihre eigene Markup und können über Frameworks und Browser hinweg geteilt werden.
class MyComponent extends HTMLElement {
connectedCallback() {
this.innerHTML = `<h1>Hello world</h1>`;
}
}
customElements.define('my-component', MyComponent);
Siehe den Pen
Demo benutzerdefinierter Elemente von Caleb Williams (@calebdwilliams)
auf CodePen.
In diesem Beispiel definieren wir <my-component>, unser ganz eigenes HTML-Element. Zugegebenermaßen tut es nicht viel, aber dies ist der grundlegende Baustein eines benutzerdefinierten Elements. Alle benutzerdefinierten Elemente müssen in irgendeiner Weise von HTMLElement erben, um beim Browser registriert zu werden.
Benutzerdefinierte Elemente existieren ohne Drittanbieter-Frameworks und die Browserhersteller setzen sich für die fortlaufende Abwärtskompatibilität der Spezifikation ein, was fast garantiert, dass Komponenten, die gemäß den Spezifikationen geschrieben wurden, keine brüchigen API-Änderungen erfahren werden. Darüber hinaus können diese Komponenten generell out-of-the-box mit den beliebtesten Frameworks von heute, einschließlich Angular, React, Vue und anderen, mit minimalem Aufwand verwendet werden.
Shadow DOM
Der Shadow DOM ist eine gekapselte Version des DOM. Dies ermöglicht es Autoren, DOM-Fragmente effektiv voneinander zu isolieren, einschließlich allem, was als CSS-Selektor verwendet werden könnte, und den damit verbundenen Stilen. Im Allgemeinen wird jeglicher Inhalt innerhalb des Gültigkeitsbereichs des Dokuments als Light DOM bezeichnet, und alles innerhalb eines Shadow-Roots wird als Shadow DOM bezeichnet.
Bei der Verwendung des Light DOM kann ein Element mit document.querySelector('selector') ausgewählt werden oder indem auf die Kinder eines beliebigen Elements mit element.querySelector('selector') zugegriffen wird. Auf dieselbe Weise können die Kinder eines Shadow-Roots durch Aufruf von shadowRoot.querySelector angesprochen werden, wobei shadowRoot eine Referenz auf das Dokumentfragment ist – der Unterschied besteht darin, dass die Kinder des Shadow-Roots nicht vom Light DOM aus auswählbar sind. Wenn wir beispielsweise einen Shadow-Root mit einem <button> darin haben, würde der Aufruf von shadowRoot.querySelector('button') unseren Button zurückgeben, aber keine Instanz des Dokument-Abfrage-Selectors wird dieses Element zurückgeben, da es zu einer anderen DocumentOrShadowRoot-Instanz gehört. Stilselektoren funktionieren auf die gleiche Weise.
In dieser Hinsicht funktioniert der Shadow DOM ähnlich wie ein <iframe>, bei dem der Inhalt vom Rest des Dokuments abgeschnitten ist; wenn wir jedoch einen Shadow-Root erstellen, haben wir immer noch die volle Kontrolle über diesen Teil unserer Seite, aber auf einen Kontext beschränkt. Dies nennen wir Kapselung.
Wenn Sie jemals eine Komponente geschrieben haben, die dieselbe id wiederverwendet oder sich auf CSS-in-JS-Tools oder CSS-Namensstrategien (wie BEM) stützt, hat Shadow DOM das Potenzial, Ihre Entwicklererfahrung zu verbessern.
Stellen Sie sich folgendes Szenario vor
<div>
<div id="example">
<!-- Pseudo-code used to designate a shadow root -->
<#shadow-root>
<style>
button {
background: tomato;
color: white;
}
</style>
<button id="button">This will use the CSS background tomato</button>
</#shadow-root>
</div>
<button id="button">Not tomato</button>
</div>
Abgesehen vom Pseudocode von <#shadow-root> (der hier verwendet wird, um die Shadow-Grenze zu kennzeichnen, die kein HTML-Element hat), ist das HTML vollständig gültig. Um einen Shadow-Root an den obigen Knoten anzuhängen, würden wir etwas wie dies ausführen:
const shadowRoot = document.getElementById('example').attachShadow({ mode: 'open' });
shadowRoot.innerHTML = `<style>
button {
color: tomato;
}
</style>
<button id="button">This will use the CSS color tomato <slot></slot></button>`;
Ein Shadow-Root kann auch Inhalte aus seinem enthaltenden Dokument mittels des <slot>-Elements enthalten. Die Verwendung eines Slots platziert Benutzereingaben aus dem äußeren Dokument an einer bestimmten Stelle in Ihrem Shadow-Root.
Siehe den Pen
Demo zur Stil-Kapselung mit Shadow DOM von Caleb Williams (@calebdwilliams)
auf CodePen.
HTML-Vorlagen
Das treffend benannte HTML-Element <template> erlaubt es uns, wiederverwendbare Code-Vorlagen innerhalb eines normalen HTML-Flusses zu erstellen, die nicht sofort gerendert werden, aber zu einem späteren Zeitpunkt verwendet werden können.
<template id="book-template">
<li><span class="title"></span> — <span class="author"></span></li>
</template>
<ul id="books"></ul>
Das obige Beispiel würde keinen Inhalt rendern, bis ein Skript die Vorlage verarbeitet, den Code instanziiert und dem Browser mitgeteilt hat, was damit zu tun ist.
const fragment = document.getElementById('book-template');
const books = [
{ title: 'The Great Gatsby', author: 'F. Scott Fitzgerald' },
{ title: 'A Farewell to Arms', author: 'Ernest Hemingway' },
{ title: 'Catch 22', author: 'Joseph Heller' }
];
books.forEach(book => {
// Create an instance of the template content
const instance = document.importNode(fragment.content, true);
// Add relevant content to the template
instance.querySelector('.title').innerHTML = book.title;
instance.querySelector('.author').innerHTML = book.author;
// Append the instance ot the DOM
document.getElementById('books').appendChild(instance);
});
Beachten Sie, dass dieses Beispiel eine Vorlage (<template id="book-template">) ohne andere Web Components-Technologie erstellt, was erneut verdeutlicht, dass die drei Technologien im Stack unabhängig oder kollektiv verwendet werden können.
Vermeintlich könnte der Verbraucher eines Dienstes, der die Template-API nutzt, eine Vorlage beliebiger Form oder Struktur schreiben, die zu einem späteren Zeitpunkt erstellt werden könnte. Eine andere Seite auf einer Website könnte denselben Dienst nutzen, aber die Vorlage auf diese Weise strukturieren:
<template id="book-template">
<li><span class="author"></span>'s classic novel <span class="title"></span></li>
</template>
<ul id="books"></ul>
Siehe den Pen
Vorlagenbeispiel von Caleb Williams (@calebdwilliams)
auf CodePen.
Das war unsere Einführung in Web Components
Da die Webentwicklung immer komplizierter wird, wird es für Entwickler wie uns sinnvoll sein, immer mehr Entwicklung an die Webplattform selbst zu delegieren, die sich weiterentwickelt hat. Die Spezifikationen für Web Components sind eine Reihe von Low-Level-APIs, die weiter wachsen und sich mit unseren sich entwickelnden Bedürfnissen als Entwickler weiterentwickeln werden.
Im nächsten Artikel werden wir uns genauer mit den HTML-Vorlagen beschäftigen. Danach werden wir eine Diskussion über benutzerdefinierte Elemente und Shadow DOM folgen lassen. Abschließend werden wir alles mit einem Blick auf höherwertige Werkzeuge und die Integration in heutige beliebte Bibliotheken und Frameworks abrunden.
Artikelserie
- Eine Einführung in Web Components (Dieser Beitrag)
- Erstellung wiederverwendbarer HTML-Vorlagen
- Creating a Custom Element from Scratch
- Kapselung von Stil und Struktur mit Shadow DOM
- Fortgeschrittene Werkzeuge für Web Components
Hallo, toller Beitrag! Schön zu sehen, dass Web Components mehr Aufmerksamkeit bekommen :)
Mir ist aufgefallen, dass Teil 5 dieser Reihe sich mit fortgeschritteneren Werkzeugen beschäftigt. Wir haben bei http://www.open-wc.org viel Arbeit in Bezug auf Werkzeuge und Web Components geleistet.
Vielleicht können wir in Kontakt treten und Ihnen bei etwas helfen? Würde mich freuen, von Ihnen zu hören!
Ich kriege schon Kopfschmerzen… aber es ist ein guter Anfang… freue mich auf das, was als Nächstes kommt ;)
Tolle Einführung!! Vielleicht wäre es gut, eine Warnung hinzuzufügen, damit Leute sich nicht XSSen (es sei denn, ich habe es übersehen).
Für unser neues, riesiges Langzeit-Unternehmensprojekt haben wir uns für Web Components und Vanilla JS anstelle von Frameworks für die Benutzeroberfläche entschieden. Das Projekt soll jahrzehntelang unterstützt werden und wir wollen später keine veralteten Frameworks (wie heute jQuery) unterstützen oder im laufenden Betrieb von einem Framework migrieren. Also werden Vanilla und WC als offizielle Standard-Spezifikation sehr lange Bestand haben.
Für kleinere Projekte und Start-ups mögen Frameworks ein Allheilmittel sein, da man viel aus dem Stegreif erstellen kann. Aber in großen Unternehmensumgebungen ist es wirklich schwer, auf eine andere Technologie zu migrieren, um auf dem neuesten Stand zu bleiben, daher spielen Standards hier für Großprojekte eine Rolle, WC ist eine sehr gute Lösung.
Ich verstehe endlich, was der Shadow DOM ist
Toller Artikel!
Gutes Tutorial, obwohl ich davon abraten würde, querySelector in Beispielen zu verwenden. Es ist sehr langsam im Vergleich zu anderen Selektoren, da es CSS parsen muss.
Danke für das Feedback. Ich würde nicht unbedingt sagen, dass
querySelectorlangsam ist, es ist nur nicht so schnell wie einige Alternativen. Es kann immer noch bis zu 7.000 Aufgaben pro Millisekunde ausführen, was ziemlich verrückt ist, wenn man wirklich darüber nachdenkt. Für die meisten Operationen macht die Bequemlichkeit und Vielseitigkeit vonquerySelectores zu einer guten Wahl, obwohl Sie absolut Recht haben, dassgetElementByIdundgetElementsByClassNameschneller sind alsquerySelector.Das sieht nach einem dringend benötigten Artikel über ein in diesen Tagen der JS-Frameworks übersehenes Thema aus. Ich werde die Serie mit großem Interesse verfolgen.
Web Components sind eine der angenehmsten Technologien, die diese Branche, das "Web", hervorgebracht hat, und es ist dieselbe Technologie, die heutzutage von allen JavaScript-Frameworks verwendet wird.
Hallo Caleb, toll, dass Web Components hier so ausführlich behandelt werden! Danke, dass Sie sich die Zeit genommen haben. Ich bin neugierig, warum Sie HTML Imports in diesem Artikel vorgestellt haben. Nach meinem Kenntnisstand wurde die Spezifikation branchenweit eingestellt und wird bald aus Chrome entfernt. Ein Großteil der Web Components-Community hat sich für ESModules (mit der Möglichkeit von HTMLModules und CSSModules in der Zukunft) als Modul/Deduplizierungsstrategie der Wahl entschieden. Warum darauf eingehen, wo es fälschlicherweise so interpretiert werden könnte, dass es aktiv Teil der Familie von Technologien ist, die Web Components jetzt und in Zukunft antreiben?
Hallo Westbrook, das ist ein fairer Punkt. Ich dachte, es gäbe genug allgemeines Wissen über HTML Imports, dass es erwähnenswert ist. Sie haben jedoch absolut Recht, dass HTML Imports zugunsten von HTML Modules veraltet sind. Einige Formulierungen hier waren verwirrend. Ich werde sehen, ob ich sie aktualisieren kann.
HTML Imports waren früher Teil der Web Component-Spezifikation, sind aber veraltet und wurden durch ES6-Modulimporte ersetzt. Chrome hat sie von Version 36 bis 72 unterstützt. Aber sie wurden entfernt.
Der Abschnitt oben „HTML Imports ist wahrscheinlich das …“ sollte HTML Modules behandeln. HTML Imports wurden in Chrome seit einigen Jahren ausgeliefert und werden nun veraltet: https://www.chromestatus.com/features/5144752345317376
Hallo Eric, danke für das Feedback. Ich glaube, beim Schreiben/Bearbeiten ist etwas bei der Übersetzung verloren gegangen. Ich werde das aktualisieren.
Das ist ein großartiger Artikel, außer dass Sie
appendChildnicht direkt auf dem DOM verwenden sollten, wenn Sie eine Schleife durchlaufen, da dies zu Layout Thrashing (d. h. das Auslösen vieler Repaints) führt. Eine Option ist stattdessen, ein Dokumentfragment zu erstellen, Ihre Elemente daran anzuhängen und *dann* dieses Fragment an das DOM anzuhängen. Ich freue mich darauf, den Rest der Serie zu lesen :)Ich würde den Verweis auf HTML-Module entfernen. Dieser Teil der Spezifikation wurde veraltet und wird in Zukunft NICHT mehr verwendet.
Hallo Caleb! Nettes Artikel :) Ich glaube, es gibt 4 Spezifikationen, die Web Components ausmachen, die vierte sind ES Modules :) Ich bin mir nicht sicher, wie viel Sie dazu sagen möchten, aber es könnte nett sein, es hinzuzufügen!
https://www.webcomponents.org/introduction
Wir erstellen seit Anfang des Jahres unser Designsystem mit Web Components. Wir haben die ShadowRoot-Option aufgegeben, da wir mehrere Skins haben und noch keinen Weg gefunden haben, diese Anforderung mit ShadowRoot umzusetzen. Auch wenn ich die Idee (als Designer) der Kapselung von Code liebe. Was ist Ihre Meinung zur Pflege von Skins mit Web Components und ShadowRoot?
Leser Jon Nyman, nach Abpfiff, daher im Auftrag von ihm gepostet
In Bezug auf CSS und Web Components ist das ein kleines Dilemma. Es gibt zwei Möglichkeiten, das CSS der Seite zu verwenden, soweit ich weiß. Erstens können Sie den DOM direkt anstelle des Shadow-Roots verwenden. Zweitens könnten Sie Slots verwenden, die das CSS der Seite verwenden. Dann können Sie Ihr CSS für Ihr benutzerdefiniertes Element mit einem Namespace versehen, sagen wir, Sie haben das benutzerdefinierte Element
<i-like-cheese>, dann könnte Ihr CSS so aussehen: