Eine Basisklasse zum Erstellen von Webkomponenten mit Lit-HTML
lit-element kann über das Lit-HTML-Element-NPM-Paket installiert werden.
lit-element können Sie Webkomponenten mit HTML-Vorlagen erstellen, die mit Literalen von JavaScript-Vorlagen ausgedrückt werden, und diese Vorlagen effizient wieder zu rendern und wieder zu rendern .
lit-element erreicht dies durch Integration von Lit-HTML und verfügt über die folgenden Funktionen:
render() -MethodenrenderCallback möglichinvalidate()this oder die Zerstörung verwendenid in der Schattenwurzel mit this.$(...)Demos finden Sie hier.
Einfach schreiben Sie Ihren HTML-Code mit lit-html , indem Sie eine render() -Methode erstellen.
import { LitElement , html } from '/src/lit-element.js' ;
class HelloWorld extends LitElement {
render ( ) {
return html `
< div style =" font-weight: bold " > Hello World </ div >
` ;
}
}
customElements . define ( 'hello-world' , HelloWorld ) < hello-world > </ hello-world >id abfragen Nachdem der Inhalt beim ersten Mal (z. B. nach connectedCallback() -Feuer) gemacht wurde, können Sie mit dieser id auf Elemente in der Schattenwurzel zugreifen this.$(...) .
Im folgenden Beispiel nennen wir this.changeColor() this.$("wrapper")
class ColorMarker extends LitElement {
changeColor ( ) {
const color = Math . random ( ) . toString ( 16 ) . substr ( 2 , 6 ) ;
// Easily query the element by id:
this . $ ( "wrapper" ) . style . backgroundColor = `# ${ color } ` ;
}
render ( ) {
return html `
< style >
div {
background-color: yellow;
}
</ style >
< button on-click = ${ ( ) => this . changeColor ( ) } >
Change background color
</ button >
< div id =" wrapper " > < slot > </ slot > </ div >
` ;
}
}
customElements . define ( 'color-marker' , ColorMarker ) ; < color-marker > Horse </ color-marker > In diesem Beispiel werden wir Eigenschaften verwenden. Jede in den statische Getter properties() definierte Eigenschaft sorgt dafür, dass der Inhalt zum richtigen Zeitpunkt erneut gerendert wird, wenn er geändert wird.
Eigenschaften können Standardwerte haben und sogar über Attribute reflektiert werden (Änderungen gehen in beide Richtungen). Anstatt Magie zu machen und Fälle nach speziellen Regeln wie upper-case und upperCase zu konvertieren, definieren Sie stattdessen ein Beispiel, an dem die Eigenschaft die Eigenschaft reflektiert werden sollte, und vermeiden daher Unklarheiten.
Beachten Sie, dass Sie bei der Verwendung von Eigenschaften vor der Verwendung der Elemente this.withProperties aufrufen müssen. Da die Methode die Klasse selbst zurückgibt, kann dies als Teil von customElements.define(...)
Beachten Sie, dass Attribute Standardwerte aus den Elementattributen selbst festgelegt werden (vorhanden oder fehlend), und daher werden Standardwerte über 'Wert' ignoriert.
import { LitElement , html } from '/src/lit-element.js' ;
class HelloWorld extends LitElement {
static get properties ( ) {
return {
uppercase : {
type : Boolean ,
attrName : "uppercase"
}
}
}
render ( ) {
return html `
< style >
.uppercase {
text-transform: uppercase;
}
</ style >
< div id =" box " class$ =" ${ this . uppercase ? 'uppercase' : '' } " >
< slot > Hello World </ slot >
</ div >
` ;
}
}
customElements . define ( 'hello-world' , HelloWorld . withProperties ( ) ) ; < hello-world > </ hello-world >
< hello-world uppercase > ¡Hola, mundo! </ hello-world > Beim Erstellen von benutzerdefinierten Elementen besteht ein gutes Muster darin, Attribute anstelle von Methoden oder Eigenschaften zu verwenden. Dies ermöglicht die Verwendung des Elements deklarativ wie <my-dialog opened> .
Für benutzerdefinierte Elemente, die nur intern in anderen benutzerdefinierten Elementen konsumiert werden, ist es oft schneller, nur auf Eigenschaften zu stützen. Dies ist auch der Fall, wenn Sie komplexe Daten wie Arrays oder Objekte weitergeben müssen.
Um es einfach zu machen, mit Attributen zu arbeiten, unterstützt lit-html-element die Zuordnung zwischen Attributen und Eigenschaften automatisch, nur indem der Name des Attributs definiert wird, das die Eigenschaft über attrName: .
Das Vorhandensein von Attributen oder nicht (auf Elementen) führt zu den tatsächlichen Werten , dh. Ein fehlendes Attribut für eine Boolesche Eigenschaft bedeutet, dass die Eigenschaft false und für alle anderen Eigentumsarten und undefined . Dies bedeutet, dass bei der Zuordnung von Eigenschaften auf Attribute kein Standardwert wie Werte je nach Anwesenheit oder nicht von Attributen definiert werden. Dies bedeutet, dass das Einstellen value: Wenn attrName: vorhanden ist.
Die Werte werden unter Verwendung ihrer Typ -Konstruktoren, dh String(attributeValue) für String , Number(attributeValue) für Number usw. konvertiert.
Boolean verfügt über eine spezielle Handhabung, um den Mustern der Webplattform zu folgen.
Aus dem HTML -Standard:
Das Vorhandensein eines booleschen Attributs auf einem Element repräsentiert den wahren Wert, und das Fehlen des Attributs repräsentiert den falschen Wert.
Wenn das Attribut vorhanden ist, muss sein Wert entweder die leere Zeichenfolge oder ein Wert sein, der eine ASCII-Fall-unempfindliche Übereinstimmung mit dem kanonischen Namen des Attributs ist, ohne dass eine führende oder nachfolgende Weißespace ist.
Array und Object werden für Attribute entleert und haben keine spezielle Handhabung. Daher werden die Werte mit ihren Konstruktoren als andere Werttypen mit Ausnahme von Boolean konvertiert.
this wird an render () für Sie übergeben, was sauberer ist. Besonders bei Zerstörungen. Sie können sie jedoch immer noch manuell verweisen.
class RenderShorthand extends LitElement {
static get properties ( ) {
return {
greeting : {
type : String ,
value : "Hello"
}
}
}
render ( { greeting } ) {
return html ` ${ greeting } World!` ;
}
}
customElements . define ( 'render-shorthand' , RenderShorthand . withProperties ( ) ) ; Wenn sich eine der Eigenschaften in properties() ändert, wird lit-element automatisch wieder rendern. Gleiches gilt für Attribute, die über attrName den Eigenschaften zugeordnet sind.
Wenn Sie manuell erneut rendern müssen, können Sie einen Neurender über einen Anruf auf invalidate() . Dadurch wird ein Mikrotask geplant, der den Inhalt kurz vor dem nächsten requestAnimationFrame rendert.
Benutzerdefinierte Elemente müssen vor ihrer Arbeit aktualisiert werden. Dies geschieht automatisch vom Browser, wenn er alle Ressourcen enthält, die es benötigt.
Dies bedeutet, dass wenn Sie ein benutzerdefiniertes Element durchführen, das von anderen lit-html-element Elementen abhängt und Eigenschaften für den Datenfluss verwenden, und dann die Eigenschaften festlegen, bevor das Element aktualisiert wird.
Es gibt eine API, bei whenAllDefined(result, container) es sich um das Problem handelt, wenn alle Abhängigkeiten verbessert wurden. Eine Möglichkeit, es zu verwenden, besteht darin, den renderCallback() zu überschreiben:
renderCallback ( ) {
if ( "resolved" in this ) {
super . renderCallback ( ) ;
} else {
whenAllDefined ( this . render ( this ) ) . then ( ( ) => {
this . resolved = true ;
this . renderCallback ( ) ;
} ) ;
}
}Sie können es jedoch trotzdem schaffen, Eigenschaften zu schatten
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;Bewache diese also auf folgende Weise:
customElements . whenDefined ( 'computed-world' ) . then ( ( ) => {
document . getElementById ( 'ninja' ) . firstName = "Ninja" ;
} ) ;Wenn Sie einige Eigenschaften benötigen, die berechnet werden und abhängig von anderen Eigenschaften aktualisiert werden, ist dies mit dem "berechneten" Wert möglich, der eine Objektmethode mit Argumenten als Zeichenfolge definierte.
Berechnete Eigenschaften aktualisieren nur , wenn alle abhängigen Eigenschaften definiert sind . Der Standardwert kann mithilfe von value:
Beachten Sie, dass berechnete Eigenschaften nicht in Attributen reflektiert werden können.
Z.B.
import { LitElement , html } from '/node_modules/lit-html-element/lit-element.js' ;
class ComputedWorld extends LitElement {
static get properties ( ) {
return {
firstName : {
type : String ,
attrName : "first-name"
} ,
doubleMessage : {
type : String ,
computed : 'computeDoubleMessage(message)'
} ,
message : {
type : String ,
computed : 'computeMessage(firstName)' ,
value : 'Hej Verden'
}
}
}
computeDoubleMessage ( message ) {
return message + " " + message ;
}
computeMessage ( firstName ) {
return `Konichiwa ${ firstName } ` ;
}
render ( ) {
return html `
< div style =" font-weight: bold " > ${ this . doubleMessage } </ div >
` ;
}
}
customElements . define ( 'computed-world' , ComputedWorld . withProperties ( ) ) < computed-world > </ computed-world >
< computed-world first-name =" Kenneth " > </ computed-world > Es ist möglich lit-html-element von TypeScript anstelle von JavaScript zu verwenden. Bei der Verwendung von TypeScript können Sie sich für die Verwendung von Dekoratoren entscheiden, anstatt die statischen Eigenschaften Accessor static get properties() zu definieren.
Bei der Verwendung von Immobiliendekoratoren wird ein solcher statischer Immobilien -Accessor ignoriert, und Sie müssen auch nicht .withProperties() anrufen.
import {
LitElement ,
html ,
TemplateResult ,
customElement ,
property ,
attribute ,
computed
} from '../../src/lit-element.js' ;
@ customElement ( 'test-element' )
export class TestElement extends LitElement {
@ computed ( 'firstName' , 'lastName' )
get fullName ( ) : string {
return ` ${ this . firstName } ${ this . lastName } ` ;
}
@ property ( ) firstName : string = 'John' ;
@ property ( ) lastName : string = 'Doe' ;
@ property ( ) human : boolean = true ;
@ property ( ) favorite : any = { fruit : 'pineapple' } ;
@ property ( ) kids : Array < string > = [ 'Peter' , 'Anna' ] ;
@ attribute ( 'mother' ) mother : string ;
@ attribute ( 'super-star' ) superStar : boolean ;
render ( ) : TemplateResult {
return html `
< h2 > Name: ${ this . fullName } </ h2 >
< h2 > Is human?: ${ human ? "yup" : "nope" } </ h2 >
< h2 > Favorites: ${ JSON . stringify ( this . favorite ) } </ h2 >
< h2 > Kids: ${ JSON . stringify ( this . kids ) } </ h2 >
< h2 > Mother: ' ${ this . mother } ' </ h2 >
< h2 > Superstar?: ' ${ this . superStar } ' </ h2 >
` ;
}
} < test-element super-star mother =" Jennifer " > </ test-element > Um Dekoratoren aus TypeScript zu verwenden, müssen Sie die experimentalDecorators -Compiler -Einstellung in Ihrem tsconfig.json aktivieren oder das Flag --experimentalDecorators verwenden.
{
"compilerOptions" : {
"experimentalDecorators" : true
}
}Mit dem oben aktiven Aktivieren können Sie Dekoratoren verwenden, müssen jedoch die Typinformationen manuell angeben:
@ property ( { type : String } )
myProperty: string ;Da der Typ oft aus der Eigenschaft abgeleitet werden kann, insbesondere in Typenkript, wo Sie den Typ definieren, fühlt sich dies wie ein bisschen doppelte Arbeit an. Glücklicherweise gibt es einen neuen Spezifikationsvorschlag, der als Metadatenreflexion bezeichnet wird und dieses Problem lösen soll. Dieser Vorschlag muss der TC39 -Arbeitsgruppe noch offiziell vorgeschlagen werden (definiert den JavaScript -Standard), aber es gibt bereits eine funktionierende Polyfill und experimentelle Unterstützung in TypeScript.
Bei der ermöglichten Metadatenreflexion ist es möglich, Eigenschaftstypen genauer zu definieren:
@ property ( ) myProperty: string ;Um Dekoratoren aus Typenkript zu verwenden, folgen Sie den folgenden Schritten aus.
emitDecoratorMetadata -Compiler -Einstellung in Ihrem tsconfig.json aktivieren oder die Flagge --emitDecoratorMetadata verwenden. {
"compilerOptions" : {
"emitDecoratorMetadata" : true
}
}$ npm install --save-dev rbuckton/reflect-metadata < script src =" /node_modules/reflect-metadata/Reflect.js " > </ script >Die folgende API -Dokumentation verwendet Web IDL.
PropertyOptions Eigenschaften werden zum Konfigurieren der Eigenschaften für das benutzerdefinierte Element verwendet. In JavaScript müssen Sie einen statischen Immobilien -Accessor namens properties implementieren, der ein Objekt zurückgibt, bei dem jede Eigenschaft dieses Objekts über eine zugehörige PropertyOptions verfügt:
class {
static get properties ( ) {
return { selfDefinedObjectProperty : ... }
}
} Das PropertyOptions Dictionary verfügt über 4 optionale Eigenschaften, die unten im Web -IDL -Format angezeigt werden.
typedef (BooleanConstructor or DateConstructor or NumberConstructor or StringConstructor or ArrayConstructor or ObjectConstructor) PropertyType ;
dictionary PropertyOptions {
attribute PropertyType type ;
attribute any value ;
attribute USVString attrName ;
attribute USVString computed ;
}type Die type -Eigenschaft ist nur optional, wenn Dekorateure und Metadaten Reflexion verwendet werden.
value Die value definiert einen Standardwert für die Eigenschaft. Bei Attribut / Eigenschaftskartierung über attrName (siehe unten) wird value ignoriert. Bei der Verwendung von Dekoratoren liegt der Wert aus der Eigenschaftsdefinition selbst:
@ property ( ) myProperty: string = "Hello World" ; attrName -Grundstück Der attrName definiert den Namen des Attributs, das sich mit der Eigenschaft und umgekehrt widerspiegeln sollte. Bei attrName werden Standardwerte stattdessen aus dem benutzerdefinierten Element ignoriert und bestimmt. abhängig von der Anwesenheit oder nicht von den Attributen.
Der Attributname ist viel in lateinischen Buchstaben (AZ), einschließlich '-' (Hyphen). Alle Attribute zu HTML-Elementen in HTML-Dokumenten werden automatisch ASCII-Lowercased und der erste Bindestrich ('-') ignoriert.
Beachten Sie, dass Datenattribute, dh. Attribute, die mit data- beginnen, sind als Eigenschaften automatisch über element.dataset zugegriffen.
Wenn zu kartierte Eigenschaften im Element festgelegt werden, wird das Attribut mit der String -Darstellung des neuen Werts aktualisiert, es sei denn, der neue Wert ist undefined , in dem das Attribut entfernt wird.
Es gibt eine Ausnahme, so wie sich die Booleschen Eigenschaften anders reflektiert. Das Festlegen der Eigenschaft auf true und das Attribut (Say attr ) ist auf die leere '' festgelegt (was bedeutet, dass Attribut vorhanden ist, dh <div attr> ). Das Einstellen der Eigenschaft auf false und das Attribut wird entfernt, dh. <div> .
Wenn die Attribute festgelegt sind, werden die Werte mit ihren Typ -Konstruktoren konvertiert, dh String(attributeValue) für String , Number(attributeValue) für Number usw.
Boolean verfügt über eine spezielle Handhabung, um den Mustern der Webplattform zu folgen.
Aus dem HTML -Standard:
Das Vorhandensein eines booleschen Attributs auf einem Element repräsentiert den wahren Wert, und das Fehlen des Attributs repräsentiert den falschen Wert.
Wenn das Attribut vorhanden ist, muss sein Wert entweder die leere Zeichenfolge oder ein Wert sein, der eine ASCII-Fall-unempfindliche Übereinstimmung mit dem kanonischen Namen des Attributs ist, ohne dass eine führende oder nachfolgende Weißespace ist.
Lesen Sie mehr im Abschnitt "Attributreflexion oben".
computed Eigenschaft Eigenschaften können aus anderen Eigenschaften unter Verwendung von computed berechnet werden. Es werden eine Zeichenfolge wie 'methodName(property1, property2)' verwendet, wobei methodName eine Methode für das Element und property1 und property2 definiert sind.
Berechnete Eigenschaften aktualisieren nur , wenn alle abhängigen Eigenschaften definiert sind . Der Standardwert kann mithilfe von value:
Beachten Sie, dass berechnete Eigenschaften nicht in Attributen reflektiert werden können.
renderCallback Der renderCallback ermöglicht benutzerdefinierte Hooks vor und nach dem Rendering.
Wenn Sie vor dem Rendern zusätzliche Arbeiten erledigen müssen, z. B. das Festlegen einer Eigenschaft basierend auf einer anderen Eigenschaft, kann eine Unterklasse renderCallback() überschreiben, um vor oder nach der Basisklasse render() zu arbeiten, einschließlich der Festlegung der abhängigen Eigenschaft vor dem render() .
withProperties()Todo:
render(HTMLElement this)TODO: Move Docs hier
async invalidate()TODO: Move Docs hier
$(DOMString id)TODO: Move Docs hier
whenAllDefined(TemplateResult result)TODO: Move Docs hier
@customElement(USVString tagname)Ein Klassendekorator zur Registrierung des benutzerdefinierten Elements
@ customElement ( 'my-element' )
class extends HTMLElement {
...
}@property(optional PropertyOptions options) Ein Immobiliendekorator für das Einbinden in das lit-html-element Eigenschaftssystem.
Wenn Sie den Eigenschaftsdekorator verwenden, müssen Sie die statischen Eigenschaften Accessor static get properties() nicht definieren.
Bei der Verwendung von Immobiliendekoratoren wird ein solcher statischer Immobilien -Accessor ignoriert, und Sie müssen auch nicht .withProperties() anrufen.
@ property ( { type : String } )
myProperty: string ;Weitere Informationen finden Sie unter Erweiterungen für Typscript.
@attribute(USVString attrName) Ein Immobiliendekorator für das Einbinden in das lit-html-element Eigenschaftssystem und eine Eigenschaft mit einem benutzerdefinierten Elementattribut.
Weitere Informationen finden Sie in der Eigenschaft attrName .
@computed(any dependency1, any dependency2, ...) Ein Immobiliendekorator für das Einbinden in das lit-html-element -Eigenschaftssystem und erstellen Sie eine Eigenschaft, die automatisch aus anderen Eigenschaften zusammenfasst.
Weitere Informationen finden Sie in der computed .
@listen(USVString eventName, (USVString or EventTarget) target) Ein Methodendekorator zum Hinzufügen eines Event -Hörers. Sie können eine Zeichenfolge für das Ziel verwenden und mit dieser id nach einem Element in der Schattenwelle suchen.
Event -Hörer werden nach dem ersten Rendering hinzugefügt, was den Shadow Dom erstellt.