Mit benutzerdefinierten Elementen können Webentwickler neue HTML-Tags definieren, vorhandene Tags erweitern und wiederverwendbare Webkomponenten erstellen.
Mit benutzerdefinierten Elementen können Webentwickler neue HTML-Tags erstellen, vorhandene HTML-Tags optimieren oder die Komponenten anderer Entwickler erweitern, verfasst wurde. Das API ist die Grundlage für Web- Komponenten. Sie ermöglicht eine standardbasierten Verfahren zur Erstellung wiederverwendbarer Komponenten Vanilla JS/HTML/CSS. Das Ergebnis: weniger Code, modularer Code und mehr Wiederverwendung in für unsere Apps.
Einführung
Der Browser ist ein hervorragendes Tool zum Strukturieren von Webanwendungen. Es ist namens HTML. Vielleicht hast du schon davon gehört! Sie ist deklarativ, übertragbar unterstützt und einfach zu arbeiten. Großartig, wie HTML auch sein mag, mit seinem Vokabular und Erweiterbarkeit sind begrenzt. Die HTML-Laufenden Google-Standard bisher keine Möglichkeit geboten hat, automatisch JS-Verhalten mit eurem Markup zu verknüpfen.
Benutzerdefinierte Elemente sind die Antwort auf die Modernisierung von HTML. und die Strukturierung mit Verhalten. Sollte der HTML-Code für ein Problem lösen, können wir ein benutzerdefiniertes Element erstellen, das dies tut. Benutzerdefiniert -Elementen vermitteln dem Browser neue Tricks und behalten gleichzeitig die Vorteile von HTML bei.
Neues Element definieren
Um ein neues HTML-Element zu definieren, benötigen wir die Leistungsfähigkeit von JavaScript!
Der globale customElements
wird zum Definieren eines benutzerdefinierten Elements und zum Unterrichten verwendet
über ein neues Tag informieren. customElements.define()
mit dem Tag-Namen aufrufen
die du erstellen möchtest, und ein JavaScript-class
, das die Basis-HTMLElement
erweitert.
Beispiel – Festlegen eines mobilen Leistenbereichs, <app-drawer>
:
class AppDrawer extends HTMLElement {...}
window.customElements.define('app-drawer', AppDrawer);
// Or use an anonymous class if you don't want a named constructor in current scope.
window.customElements.define('app-drawer', class extends HTMLElement {...});
Nutzungsbeispiel:
<app-drawer></app-drawer>
Ein benutzerdefiniertes Element funktioniert genauso wie
mit einem <div>
oder einem anderen Element. Instanzen können
auf der Seite deklariert werden,
dynamisch in JavaScript erstellt oder Ereignis-Listener angehängt werden usw.
finden Sie weitere Beispiele.
JavaScript API eines Elements definieren
Die Funktionalität eines benutzerdefinierten Elements wird mit einem ES2015 definiert.
class
das sich über HTMLElement
erstreckt. Durch das Erweitern von HTMLElement
wird sichergestellt, dass das benutzerdefinierte Element
übernimmt die gesamte DOM-API und bedeutet alle Eigenschaften/Methoden, die Sie der
-Klasse in die DOM-Schnittstelle des Elements integriert. Im Wesentlichen verwenden Sie die Klasse, um
Erstellen Sie eine öffentliche JavaScript API für Ihr Tag.
Beispiel – Definition der DOM-Schnittstelle von <app-drawer>
:
class AppDrawer extends HTMLElement {
// A getter/setter for an open property.
get open() {
return this.hasAttribute('open');
}
set open(val) {
// Reflect the value of the open property as an HTML attribute.
if (val) {
this.setAttribute('open', '');
} else {
this.removeAttribute('open');
}
this.toggleDrawer();
}
// A getter/setter for a disabled property.
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
// Reflect the value of the disabled property as an HTML attribute.
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
// Can define constructor arguments if you wish.
constructor() {
// If you define a constructor, always call super() first!
// This is specific to CE and required by the spec.
super();
// Setup a click listener on <app-drawer> itself.
this.addEventListener('click', e => {
// Don't toggle the drawer if it's disabled.
if (this.disabled) {
return;
}
this.toggleDrawer();
});
}
toggleDrawer() {
// ...
}
}
customElements.define('app-drawer', AppDrawer);
In diesem Beispiel erstellen wir eine Leiste mit dem Attribut open
, disabled
und einer toggleDrawer()
-Methode. Außerdem werden Eigenschaften als HTML dargestellt.
Attribute enthalten.
Eine tolle Funktion von benutzerdefinierten Elementen ist, dass this
in einer Klassendefinition
sich auf das DOM-Element selbst, d.h. die Instanz der Klasse. In unserem
Beispiel: this
bezieht sich auf <app-drawer>
. So (😉) kann das Element
einen click
-Listener an sich selbst anhängen! Und Sie sind nicht auf Event-Listener beschränkt.
Die gesamte DOM API ist im Elementcode verfügbar. Verwenden Sie this
, um auf
Eigenschaften des Elements, untergeordnete Elemente prüfen (this.children
), Knoten abfragen
(this.querySelectorAll('.items')
) usw.
Regeln zum Erstellen benutzerdefinierter Elemente
- Der Name eines benutzerdefinierten Elements muss einen Bindestrich (-) enthalten. Also
<x-tags>
,<my-element>
und<my-awesome-app>
sind gültige Namen, während<tabs>
und<foo_bar>
nicht. Diese Anforderung ist erforderlich, damit der HTML-Parser benutzerdefinierte Elemente von regulären Elementen unterscheiden. Außerdem wird so sichergestellt, Kompatibilität beim Hinzufügen neuer Tags zu HTML. - Sie können ein Tag nur einmal registrieren. Wenn Sie dies versuchen,
DOMException
ausgeben. Sobald Sie dem Browser ein neues Tag mitgeteilt haben, . Keine Rücknahmen. - Benutzerdefinierte Elemente dürfen nicht selbstschließend sein, da bei HTML nur einige wenige Elemente zulässig sind.
Elemente
selbstschließend sein. Schreiben Sie immer ein schließendes Tag.
(
<app-drawer></app-drawer>
).
Reaktionen auf benutzerdefinierte Elemente
Mit einem benutzerdefinierten Element können spezielle Lebenszyklus-Hooks zum Ausführen von Code während interessante Zeiten ihrer Existenz. Diese werden als benutzerdefiniertes Element Reaktionen.
Name | Angerufen, wenn |
---|---|
constructor |
Eine Instanz des -Elements ist
erstellten oder aktualisierten. Nützlich für die Initialisierung
Ereignis-Listener einrichten oder
zum Erstellen eines Schattendoms.
Weitere Informationen finden Sie in der
<ph type="x-smartling-placeholder"></ph>
spec
.constructor
|
connectedCallback |
Wird jedes Mal aufgerufen, wenn der wird in das DOM eingefügt. Nützlich zum Ausführen von Einrichtungscode, z. B. Abrufen von Ressourcen oder Rendern. Im Allgemeinen sollten Sie versuchen, bis zu diesem Zeitpunkt. |
disconnectedCallback |
Wird jedes Mal aufgerufen, wenn das Element aus dem DOM entfernt wird. Nützlich für Clean-up-Code ausgeführt wird. |
attributeChangedCallback(attrName, oldVal, newVal) |
Wird aufgerufen, wenn ein beobachtetes Attribut
hinzugefügt, entfernt,
aktualisiert oder ersetzt wurden. Wird auch für Anfangswerte aufgerufen
Ein Element wird vom Parser erstellt.
aktualisiert. Hinweis: Nur
Attribute, die in der observedAttributes -Property aufgeführt sind,
diesen Rückruf empfangen.
|
adoptedCallback |
Die
benutzerdefiniertes Element wurde in ein neues document verschoben (z.B.
jemand namens document.adoptNode(el) ).
|
Reaktions-Callbacks sind synchron. Wenn jemand el.setAttribute()
anruft
für Ihr Element, ruft der Browser sofort attributeChangedCallback()
auf.
Entsprechend erhalten Sie ein disconnectedCallback()
direkt, nachdem Ihr Element
aus dem DOM entfernt werden (z.B. wenn der Nutzer el.remove()
aufruft).
Beispiel:Reaktionen für benutzerdefinierte Elemente zu <app-drawer>
hinzufügen:
class AppDrawer extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// ...
}
connectedCallback() {
// ...
}
disconnectedCallback() {
// ...
}
attributeChangedCallback(attrName, oldVal, newVal) {
// ...
}
}
Definieren Sie Reaktionen, wenn es Sinn ergibt. Wenn Ihr Element ausreichend komplex ist
und eine Verbindung zu IndexedDB in connectedCallback()
herstellt, führen Sie
Bereinigungsarbeiten in disconnectedCallback()
. Aber sei vorsichtig! Sie können sich nicht darauf verlassen,
das unter allen Umständen aus dem DOM entfernt wird. Beispiel:
disconnectedCallback()
wird nie aufgerufen, wenn der Nutzer den Tab schließt.
Eigenschaften und Attribute
Attribute auf Attribute anwenden
Es ist üblich, dass HTML-Eigenschaften ihren Wert im DOM als
HTML-Attribut. Das ist beispielsweise der Fall, wenn die Werte von hidden
oder id
in
JS:
div.id = 'my-id';
div.hidden = true;
werden die Werte als Attribute auf das Live-DOM angewendet:
<div id="my-id" hidden>
Dies wird als „reflektierende Eigenschaften von Attribute“. Dies ist bei fast jeder HTML-Property möglich. Warum? Attribute sind auch nützlich für Deklaratives Konfigurieren eines Elements und bestimmter APIs wie Barrierefreiheit und CSS Selektoren funktionieren nur mit Attributen.
Das Reflektieren einer Eigenschaft ist überall dort nützlich, wo Sie das DOM des Elements mit dem JavaScript-Status synchron. Ein Grund, warum Sie reflektiert eine -Eigenschaft, damit benutzerdefinierte Stile angewendet werden, wenn sich der JS-Zustand ändert.
Erinnern Sie sich an unsere <app-drawer>
. Ein Nutzer dieser Komponente möchte sie möglicherweise ausblenden.
und/oder Nutzerinteraktionen verhindern, wenn sie deaktiviert sind:
app-drawer[disabled] {
opacity: 0.5;
pointer-events: none;
}
Wenn das Attribut disabled
in JS geändert wird, soll dieses Attribut
wurde dem DOM hinzugefügt, damit die Auswahl des Nutzers übereinstimmt. Das Element kann dazu beitragen,
durch reflektieren des Werts an ein Attribut desselben Namens:
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
// Reflect the value of `disabled` as an attribute.
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
this.toggleDrawer();
}
Änderungen an Attributen beobachten
HTML-Attribute sind eine bequeme Möglichkeit für Nutzer, den Anfangszustand zu deklarieren:
<app-drawer open disabled></app-drawer>
Elemente können auf Attributänderungen reagieren, indem sie eine
attributeChangedCallback
Der Browser ruft diese Methode bei jeder Änderung auf
zu Attributen, die im Array observedAttributes
aufgeführt sind.
class AppDrawer extends HTMLElement {
// ...
static get observedAttributes() {
return ['disabled', 'open'];
}
get disabled() {
return this.hasAttribute('disabled');
}
set disabled(val) {
if (val) {
this.setAttribute('disabled', '');
} else {
this.removeAttribute('disabled');
}
}
// Only called for the disabled and open attributes due to observedAttributes
attributeChangedCallback(name, oldValue, newValue) {
// When the drawer is disabled, update keyboard/screen reader behavior.
if (this.disabled) {
this.setAttribute('tabindex', '-1');
this.setAttribute('aria-disabled', 'true');
} else {
this.setAttribute('tabindex', '0');
this.setAttribute('aria-disabled', 'false');
}
// TODO: also react to the open attribute changing.
}
}
In diesem Beispiel legen wir zusätzliche Attribute für <app-drawer>
fest, wenn ein
Das Attribut „disabled
“ wurde geändert. Auch wenn wir das hier nicht tun,
auch attributeChangedCallback
verwenden, um eine JS-Eigenschaft mit ihrer
.
Element upgrades
Progressive HTML-Optimierung
Wie Sie bereits wissen, werden benutzerdefinierte Elemente durch Aufrufen
customElements.define()
Das bedeutet jedoch nicht, dass Sie eine
auf einmal benutzerdefinierte Elemente.
Benutzerdefinierte Elemente können verwendet werden, bevor ihre Definition registriert wird.
Progressive Enhancement ist eine Funktion benutzerdefinierter Elemente. Mit anderen Worten: Sie können
eine Reihe von <app-drawer>
-Elementen auf der Seite deklarieren und niemals
customElements.define('app-drawer', ...)
. Das liegt daran, dass der
Browser mögliche benutzerdefinierte Elemente aufgrund von unbekannter
-Tags. Der Aufruf von define()
und die Verleihung eines vorhandenen
mit einer Klassendefinition wird als "Elementupgrades" bezeichnet.
Wenn Sie wissen möchten, wann ein Tag-Name definiert wird, können Sie
window.customElements.whenDefined()
Es gibt ein Promise zurück, das aufgelöst wird, wenn der
-Element definiert wird.
customElements.whenDefined('app-drawer').then(() => {
console.log('app-drawer defined');
});
Beispiel – Arbeit verzögern, bis eine Gruppe von untergeordneten Elementen aktualisiert wurde
<share-buttons>
<social-button type="twitter"><a href="...">Twitter</a></social-button>
<social-button type="fb"><a href="...">Facebook</a></social-button>
<social-button type="plus"><a href="...">G+</a></social-button>
</share-buttons>
// Fetch all the children of <share-buttons> that are not defined yet.
let undefinedButtons = buttons.querySelectorAll(':not(:defined)');
let promises = [...undefinedButtons].map((socialButton) => {
return customElements.whenDefined(socialButton.localName);
});
// Wait for all the social-buttons to be upgraded.
Promise.all(promises).then(() => {
// All social-button children are ready.
});
Elementdefinierter Inhalt
Benutzerdefinierte Elemente können ihren eigenen Inhalt mithilfe der darin enthaltenen DOM-APIs verwalten -Elementcode. In diesem Fall sind Reaktionen sehr praktisch.
Beispiel: Erstellen Sie ein Element mit Standard-HTML:
customElements.define('x-foo-with-markup', class extends HTMLElement {
connectedCallback() {
this.innerHTML = "<b>I'm an x-foo-with-markup!</b>";
}
// ...
});
Das Deklarieren dieses Tags führt zu:
<x-foo-with-markup>
<b>I'm an x-foo-with-markup!</b>
</x-foo-with-markup>
// TODO: DevSite - Codebeispiel entfernt, da Inline-Event-Handler verwendet wurden
Element erstellen, das Shadow DOM verwendet
Mit Shadow DOM kann ein Element einen Teil des Elements DOM, das vom Rest der Seite getrennt ist. Sie können sich sogar die gesamte App in einem einzigen Tag verwenden:
<!-- chat-app's implementation details are hidden away in Shadow DOM. -->
<chat-app></chat-app>
Um Shadow DOM in einem benutzerdefinierten Element zu verwenden, rufen Sie this.attachShadow
in Ihrem
constructor
:
let tmpl = document.createElement('template');
tmpl.innerHTML = `
<style>:host { ... }</style> <!-- look ma, scoped styles -->
<b>I'm in shadow dom!</b>
<slot></slot>
`;
customElements.define('x-foo-shadowdom', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
// Attach a shadow root to the element.
let shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(tmpl.content.cloneNode(true));
}
// ...
});
Nutzungsbeispiel:
<x-foo-shadowdom>
<p><b>User's</b> custom text</p>
</x-foo-shadowdom>
<!-- renders as -->
<x-foo-shadowdom>
#shadow-root
<b>I'm in shadow dom!</b>
<slot></slot> <!-- slotted content appears here -->
</x-foo-shadowdom>
Benutzerdefinierter Text des Nutzers
// TODO: DevSite - Codebeispiel entfernt, da Inline-Event-Handler verwendet wurden
Elemente aus einem <template>
erstellen
Für diejenigen, die ihn nicht kennen, finden Sie hier die <template>
Element
können Sie DOM-Fragmente deklarieren, die geparst, beim Seitenaufbau inaktiv und
und kann später zur Laufzeit aktiviert werden. Das ist ein weiteres API-Primitive im Web.
Familie der Komponenten. Vorlagen sind ein idealer Platzhalter, um
Struktur eines benutzerdefinierten Elements.
Beispiel:Registrieren eines Elements mit Shadow DOM-Inhalten, die aus einem
<template>
:
<template id="x-foo-from-template">
<style>
p { color: green; }
</style>
<p>I'm in Shadow DOM. My markup was stamped from a <template>.</p>
</template>
<script>
let tmpl = document.querySelector('#x-foo-from-template');
// If your code is inside of an HTML Import you'll need to change the above line to:
// let tmpl = document.currentScript.ownerDocument.querySelector('#x-foo-from-template');
customElements.define('x-foo-from-template', class extends HTMLElement {
constructor() {
super(); // always call super() first in the constructor.
let shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(tmpl.content.cloneNode(true));
}
// ...
});
</script>
Diese wenigen Codezeilen machen es möglich. Sehen wir uns an, am:
- Wir definieren ein neues Element in HTML:
<x-foo-from-template>
- Das Shadow DOM des Elements wird aus einem
<template>
erstellt - Dank des Shadow DOM ist das DOM des Elements lokal beim Element.
- Der interne CSS-Code des Elements wird dank des Shadow DOM auf das Element beschränkt.
Ich befinde mich in Shadow DOM. Mein Markup wurde aus einer <template> gestempelt.
// TODO: DevSite - Codebeispiel entfernt, da Inline-Event-Handler verwendet wurden
Benutzerdefiniertes Element gestalten
Auch wenn Ihr Element mithilfe von Shadow DOM seinen eigenen Stil definiert, können Nutzer Stile Ihr benutzerdefiniertes Element von ihrer Seite entfernen. Diese werden als „benutzerdefinierte Stile“ bezeichnet.
<!-- user-defined styling -->
<style>
app-drawer {
display: flex;
}
panel-item {
transition: opacity 400ms ease-in-out;
opacity: 0.3;
flex: 1;
text-align: center;
border-radius: 50%;
}
panel-item:hover {
opacity: 1.0;
background: rgb(255, 0, 255);
color: white;
}
app-panel > panel-item {
padding: 5px;
list-style: none;
margin: 0 7px;
}
</style>
<app-drawer>
<panel-item>Do</panel-item>
<panel-item>Re</panel-item>
<panel-item>Mi</panel-item>
</app-drawer>
Sie fragen sich vielleicht, wie die CSS-Spezifität funktioniert, wenn das Element über Stile verfügt. die im Shadow DOM definiert sind. In puncto Spezifität ist der Stil der Nutzenden entscheidend. Sie werden immer den elementdefinierten Stil überschreiben. Weitere Informationen hierzu finden Sie im Abschnitt Ein Element erstellen das Shadow DOM verwendet.
Stile für nicht registrierte Elemente festlegen
Bevor ein Element aktualisiert wird, können Sie in CSS mithilfe der Methode
:defined
. Dies ist nützlich, wenn Sie eine Komponente vorab gestalten möchten. Für
Sie können beispielsweise Layout- oder andere visuelle Elemente verhindern, indem Sie undefinierte
und einblenden, wenn
sie definiert wurden.
Beispiel: Blenden Sie <app-drawer>
aus, bevor es definiert wird:
app-drawer:not(:defined) {
/* Pre-style, give layout, replicate app-drawer's eventual styles, etc. */
display: inline-block;
height: 100vh;
opacity: 0;
transition: opacity 0.3s ease-in-out;
}
Nachdem <app-drawer>
definiert wurde, wird der Selektor (app-drawer:not(:defined)
)
stimmt nicht mehr überein.
Elemente erweitern
Die Custom Elements API ist nützlich zum Erstellen neuer HTML-Elemente, sie ist aber auch nützlich zur Erweiterung anderer benutzerdefinierter Elemente oder sogar des integrierten HTML-Codes des Browsers.
Benutzerdefiniertes Element erweitern
Zum Erweitern eines weiteren benutzerdefinierten Elements wird dessen Klassendefinition erweitert.
Beispiel: Erstellen Sie <fancy-app-drawer>
, das <app-drawer>
erweitert:
class FancyDrawer extends AppDrawer {
constructor() {
super(); // always call super() first in the constructor. This also calls the extended class' constructor.
// ...
}
toggleDrawer() {
// Possibly different toggle implementation?
// Use ES2015 if you need to call the parent method.
// super.toggleDrawer()
}
anotherMethod() {
// ...
}
}
customElements.define('fancy-app-drawer', FancyDrawer);
Erweitern von nativen HTML-Elementen
Angenommen, Sie möchten ein ansprechendes <button>
-Element erstellen. Anstatt die
Verhalten und der Funktionalität von <button>
hat, ist es besser, schrittweise nach und nach
können Sie das vorhandene Element mit benutzerdefinierten Elementen optimieren.
Ein benutzerdefiniertes integriertes Element ist ein benutzerdefiniertes Element, das eine der die integrierten HTML-Tags des Browsers. Der Hauptvorteil der Erweiterung einer bestehenden -Element besteht darin, alle seine Funktionen zu erhalten (DOM-Eigenschaften, Methoden, Zugänglichkeit). Es gibt keinen besseren Weg, ein progressives Web zu schreiben. als vorhandenen HTML-Code schrittweise zu verbessern. Elemente.
Um ein Element zu erweitern, müssen Sie eine Klassendefinition erstellen, die
aus der richtigen DOM-Schnittstelle. Beispiel: Ein benutzerdefiniertes Element, das
<button>
muss von HTMLButtonElement
anstelle von HTMLElement
übernehmen.
Ebenso muss ein Element, das <img>
erweitert, HTMLImageElement
erweitern.
Beispiel – <button>
erweitern:
// See https://html.spec.whatwg.org/multipage/indices.html#element-interfaces
// for the list of other DOM interfaces.
class FancyButton extends HTMLButtonElement {
constructor() {
super(); // always call super() first in the constructor.
this.addEventListener('click', e => this.drawRipple(e.offsetX, e.offsetY));
}
// Material design ripple animation.
drawRipple(x, y) {
let div = document.createElement('div');
div.classList.add('ripple');
this.appendChild(div);
div.style.top = `${y - div.clientHeight/2}px`;
div.style.left = `${x - div.clientWidth/2}px`;
div.style.backgroundColor = 'currentColor';
div.classList.add('run');
div.addEventListener('transitionend', (e) => div.remove());
}
}
customElements.define('fancy-button', FancyButton, {extends: 'button'});
Der Aufruf von define()
ändert sich geringfügig, wenn eine native Anzeige erweitert wird.
-Elements. Der erforderliche dritte Parameter teilt dem Browser mit,
sich ausweiten kann. Dies ist notwendig, da viele HTML-Tags dasselbe DOM verwenden.
. <section>
, <address>
und <em>
haben alle etwas geteilt
HTMLElement
; Sowohl <q>
als auch <blockquote>
teilen HTMLQuoteElement
. usw...
Wenn Sie {extends: 'blockquote'}
angeben, weiß der Browser, dass Sie
versprühten <blockquote>
statt <q>
. Siehe HTML
spec
finden Sie eine vollständige Liste der HTML-DOM-Schnittstellen.
Nutzer eines benutzerdefinierten integrierten Elements können es auf verschiedene Arten verwenden. Sie können
deklarieren Sie sie, indem Sie dem nativen Tag das Attribut is=""
hinzufügen:
<!-- This <button> is a fancy button. -->
<button is="fancy-button" disabled>Fancy button!</button>
eine Instanz in JavaScript erstellen:
// Custom elements overload createElement() to support the is="" attribute.
let button = document.createElement('button', {is: 'fancy-button'});
button.textContent = 'Fancy button!';
button.disabled = true;
document.body.appendChild(button);
oder verwenden Sie den new
-Operator:
let button = new FancyButton();
button.textContent = 'Fancy button!';
button.disabled = true;
Hier ein weiteres Beispiel für die Erweiterung von <img>
.
Beispiel – <img>
erweitern:
customElements.define('bigger-img', class extends Image {
// Give img default size if users don't specify.
constructor(width=50, height=50) {
super(width * 10, height * 10);
}
}, {extends: 'img'});
Nutzer deklarieren diese Komponente als:
<!-- This <img> is a bigger img. -->
<img is="bigger-img" width="15" height="20">
oder erstellen Sie eine Instanz in JavaScript:
const BiggerImage = customElements.get('bigger-img');
const image = new BiggerImage(15, 20); // pass constructor values like so.
console.assert(image.width === 150);
console.assert(image.height === 200);
Sonstige Details
Unbekannte und nicht definierte benutzerdefinierte Elemente
HTML ist wenig benutzerfreundlich und flexibel. Erklären Sie z. B.,
<randomtagthatdoesntexist>
pro Seite und der Browser ist zufrieden.
und akzeptieren. Warum funktionieren nicht standardmäßige Tags? Die Antwort ist die HTML-
Spezifikation
dies zulässt. Elemente, die nicht in der Spezifikation definiert sind, werden geparst als
HTMLUnknownElement
Dasselbe gilt für benutzerdefinierte Elemente. Potenzielle benutzerdefinierte Elemente werden geparst
als HTMLElement
, wenn sie mit einem gültigen Namen (einschließlich "-") erstellt wurden. Ich
können Sie dies in einem Browser überprüfen,
der benutzerdefinierte Elemente unterstützt. Starten Sie die Konsole:
Drücken Sie Ctrl + Ctrl + Ctrl (oder Ctrl + Ctrl + Ctrl auf einem Mac) und fügen Sie den
folgenden Codezeilen aus:
// "tabs" is not a valid custom element name
document.createElement('tabs') instanceof HTMLUnknownElement === true
// "x-tabs" is a valid custom element name
document.createElement('x-tabs') instanceof HTMLElement === true
API-Referenz
Der globale customElements
definiert nützliche Methoden für die Arbeit mit benutzerdefinierten
Elemente.
define(tagName, constructor, options)
Definiert ein neues benutzerdefiniertes Element im Browser.
Beispiel
customElements.define('my-app', class extends HTMLElement { ... });
customElements.define(
'fancy-button', class extends HTMLButtonElement { ... }, {extends: 'button'});
get(tagName)
Gibt bei Angabe eines gültigen Tag-Namens für ein benutzerdefiniertes Element den Konstruktor des Elements zurück.
Gibt undefined
zurück, wenn keine Elementdefinition registriert wurde.
Beispiel
let Drawer = customElements.get('app-drawer');
let drawer = new Drawer();
whenDefined(tagName)
Gibt ein Promise zurück, das aufgelöst wird, wenn das benutzerdefinierte Element definiert ist. Wenn die -Element bereits definiert ist, muss sofort aufgelöst werden. Wird abgelehnt, wenn der folgende Tag-Name nicht lautet: einen gültigen Namen für das benutzerdefinierte Element.
Beispiel
customElements.whenDefined('app-drawer').then(() => {
console.log('ready!');
});
Verlauf und Browserunterstützung
Wenn Sie in den letzten Jahren Webkomponenten folgen,
wissen, dass in Chrome 36+ eine Version der Custom Elements API implementiert ist, bei der
document.registerElement()
statt customElements.define()
. Das ist jetzt
als nicht mehr unterstützte Version des Standards v0 an.
customElements.define()
ist aktuell angesagt und welche Browseranbieter sind da
mit der Umsetzung beginnen. Es heißt Custom Elements v1.
Wenn du Interesse an der alten Version 0 hast, sieh dir die html5rocks
Unterstützte Browser
Chrome 54 (Status), Safari 10.1 (status) und Firefox 63 (Status) Benutzerdefinierte Elemente (Version 1). Edge hat begonnen Entwicklung.
Um benutzerdefinierte Elemente zu erkennen, müssen Sie prüfen, ob folgende Elemente vorhanden sind:
window.customElements
:
const supportsCustomElementsV1 = 'customElements' in window;
Polyfill
Solange die Browserunterstützung nicht allgemein verfügbar ist, Eigenständiger Polyfill die für Custom Elements v1 verfügbar sind. Wir empfehlen jedoch die Verwendung von webcomponents.js loader um die Webkomponenten-Polyfills optimal zu laden. Ladeprogramm verwendet die Feature-Erkennung, um nur die erforderlichen Pollyfills asynchron zu laden die für den Browser erforderlich sind.
Installieren:
npm install --save @webcomponents/webcomponentsjs
Verwendung:
<!-- Use the custom element on the page. -->
<my-element></my-element>
<!-- Load polyfills; note that "loader" will load these async -->
<script src="node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js" defer></script>
<!-- Load a custom element definitions in `waitFor` and return a promise -->
<script type="module">
function loadScript(src) {
return new Promise(function(resolve, reject) {
const script = document.createElement('script');
script.src = src;
script.onload = resolve;
script.onerror = reject;
document.head.appendChild(script);
});
}
WebComponents.waitFor(() => {
// At this point we are guaranteed that all required polyfills have
// loaded, and can use web components APIs.
// Next, load element definitions that call `customElements.define`.
// Note: returning a promise causes the custom elements
// polyfill to wait until all definitions are loaded and then upgrade
// the document in one batch, for better performance.
return loadScript('my-element.js');
});
</script>
Fazit
Benutzerdefinierte Elemente bieten uns ein neues Tool zum Definieren neuer HTML-Tags im Browser und
wiederverwendbaren Komponenten. Kombinieren Sie sie mit der anderen neuen Plattform.
wie Shadow DOM und <template>
. Wir erkennen,
von Web Components:
- Browserübergreifend (Webstandard) zum Erstellen und Erweitern wiederverwendbarer Komponenten.
- Erfordert keine Bibliothek oder kein Framework. Vanilla JS/HTML FTW!
- Stellt ein vertrautes Programmiermodell bereit. sondern lediglich DOM/CSS/HTML.
- Funktioniert gut mit anderen neuen Webplattformfunktionen (Shadow DOM,
<template>
, CSS). benutzerdefinierte Eigenschaften usw.) - Eng in die Entwicklertools des Browsers integriert.
- Nutzen Sie vorhandene Bedienungshilfen.