Verarbeiten von Ereignissen in Lightning-Webkomponenten
Lernziele
Nachdem Sie diese Lektion abgeschlossen haben, sind Sie in der Lage, die folgenden Aufgaben auszuführen:
- Erstellen einer Anwendung, die mehrere Komponenten enthält
- Beschreiben der Dateistruktur einer komplexen Komponente
- Verarbeiten von Ereignissen
Ein Ereignis auf seinem Weg
Sie haben eine Komponente erstellt und sie in eine Organisation übertragen. Fügen wir zunächst etwas Interaktivität in Form von Ereignisverarbeitung hinzu. Wir folgen dem Weg eines Ereignisses durch verschiedene Komponenten für eine anspruchsvolle Ereignisverarbeitung in einer Anwendung. Diese Anwendung ist eine Produktauswahl für ein Fahrradgeschäft. Die Benutzer klicken auf den Namen und das Bild eines Fahrrads, um weitere Details anzuzeigen.
Diese Anwendung besteht aus vier Komponenten, die zusammenwirken.
-
tile: zeigt einen einzelnen Artikel an.
-
list: ordnet die Kacheln an.
-
detail: zeigt die Details eines Artikels an, wenn auf eine Kachel geklickt wird (ähnlich der bikeCard, die Sie gerade erstellt haben).
-
selector: enthält den gesamten Satz von Komponenten. Eine Containerkomponente ist nicht erforderlich, wir verwenden hier jedoch eine, um die Ereignisverarbeitung zu vereinfachen.
Auf dem jetzigen Stand verwendet die Anwendung eine Datendatei, um statische Daten für Tests zu laden. In der nächsten Lektion erfahren Sie, wie Sie dynamische Daten aus einer Organisation abrufen.
Zusammensetzung der Komponenten
Fügen wir unserem Projekt einige Dateien hinzu, die wir in einer Organisation bereitstellen können.
- Laden Sie die Dateien für diese App hier herunter: Fahrrad-Auswahlanwendung für Trailhead.
- Entpacken Sie die Dateien in den Ordner force-app/main/default/lwc des bikeCard-Projekts.
Beziehungen zwischen den Komponenten
In dieser Anwendung arbeiten mehrere Komponenten zusammen, einige Komponenten sind in anderen Komponenten verschachtelt. Gerade so, wie Sie HTML-Elemente ineinander verschachteln, können Lightning-Webkomponenten – bei denen es sich um benutzerdefinierte HTML-Elemente handelt – in andere Lightning-Webkomponenten verschachtelt werden.
In unserem Dateisystem geben die Ordner der Komponenten nicht wirklich Aufschluss über die Beziehungen zwischen ihnen.
Sehen wir uns in einem Diagramm an, wie die Komponenten auf der Ebene der Benutzeroberfläche verschachtelt sind.
Durch Betrachten der Dateien können Sie erkennen, dass die Auswahlkomponente das Layout der Seite übernimmt und die Listen- (c-list
) und Detailkomponenten (c-detail
) rendert.
<template> <div class="wrapper"> <header class="header">Select a Bike</header> <section class="content"> <div class="columns"> <main class="main" > <c-list onproductselected={handleProductSelected}></c-list> </main> <aside class="sidebar-second"> <c-detail product-id={selectedProductId}></c-detail> </aside> </div> </section> </div> </template>
Aktualisieren Sie "detail.html" mit folgendem Code:
<template> <template lwc:if={product}> <div class="container"> <div>{product.fields.Name.value}</div> <div class="price">{product.fields.MSRP__c.displayValue}</div> <div class="description">{product.fields.Description__c.value}</div> <img class="product-img" src={product.fields.Picture_URL__c.value} alt={product.fields.Name.value}/> <p> <lightning-badge label={product.fields.Material__c.value}></lightning-badge> <lightning-badge label={product.fields.Level__c.value}></lightning-badge> </p> <p> <lightning-badge label={product.fields.Category__c.value}></lightning-badge> </p> </div> </template> <template lwc:else> <div>Select a bike</div> </template> </template>
Beim Blick in "detail.html" können Sie das bedingte Rendering sehen (lwc:if={product}
und lwc:else
). Wenn in der Liste nichts ausgewählt wurde, kommt eine Nachricht zur Anzeige, die den Benutzer auffordert, etwas auszuwählen. Wenn etwas ausgewählt wird, werden die Fahrradinformationen angezeigt.
Die Listenkomponente rendert verschiedene Kachelkomponenten (c-tile
), eine für jedes in den Daten enthaltene Fahrrad. Diese Verschachtelung wird im HTML-Code für jede übergeordnete Komponente erreicht. Beispielsweise hat die Listenkomponente den folgenden HTML-Code, einschließlich der Kachelkomponente als c-tile
.
<template> <div class="container"> <template for:each={bikes} for:item="bike"> <c-tile key={bike.fields.Id.value} product={bike} ontileclick={handleTileClick}></c-tile> </template> </div> </template>
Beachten Sie, wie jede Iteration des Fahrradelements eine neue Kachelkomponente hervorbringt. Durch einfachen Einschluss des c-tile
-Komponenten-Tags wird jede Kachelkomponente zu ihrem untergeordneten Element. Die div-Klassendefinition “container” wird zu Stilzwecken verwendet, damit Sie die Anordnung der Kacheln steuern können. Wenn Sie sich "list.css" ansehen, werden Sie bemerken, dass sie den Inhalt umschließt.
.container { display: flex; flex-direction: row; flex-wrap: wrap; }
Die Über-/Unterordnungsbeziehung ist wichtig, nicht nur für den Entwurf der Anwendung, sondern auch für die Ereignisverarbeitung.
Sehen wir uns die Ereignisverarbeitung etwas genauer an.
Ereignisse aufwärts, Eigenschaften abwärts
In einer komplexen Komponente (einer, die mehrere übergeordnete und untergeordnete Komponenten enthält), können die Komponenten nach oben und unten kommunizieren.
- Die untergeordnete Komponente "c-todo-item" verteilt ein Ereignis an die übergeordnete Komponente "c-todo-app". Beispielsweise kann die untergeordnete Komponente ein Ereignisobjekt an die übergeordnete Komponente übergeben, wenn ein Benutzer auf eine Schaltfläche klickt, sodass die übergeordnete Komponente das Ereignis verarbeiten und die aktuelle Seite ändern kann.
- Die übergeordnete c-todo-app-Komponente übergibt eine Eigenschaft oder ruft eine Methode der untergeordneten Komponente auf. So kann die übergeordnete Komponente beispielsweise einen Textwert in einer untergeordneten Komponente festlegen oder eine Methode in der untergeordneten Komponente aufrufen.
Sehen wir uns an, wie diese Kommunikation funktioniert.
Übergeben von Informationen nach oben
Informationen können mithilfe von Ereignissen und Ereignis-Listenern nach oben übergeben werden.
Die untergeordnete Komponente verteilt das Ereignis, und die übergeordnete Komponente lauscht darauf. Zum Verteilen des Ereignisses gehört das Erstellen eines Ereignisobjekts, das die untergeordnete Komponente an die übergeordnete Komponente übergeben kann. Die übergeordnete Komponente verfügt über einen Handler, um auf das Ereignis zu reagieren.
Eine untergeordnete Komponente wie diese enthält beispielsweise eine nextHandler()
-Methode, die mit CustomEvent()
ein einfaches Ereignisobjekt erstellt und den Ereignistyp "next" ausgibt, wenn der Benutzer auf die Schaltfläche Next (Weiter) klickt (diese Komponenten sollten nicht erstellt werden).
// todoItem.js import { LightningElement } from 'lwc'; ... nextHandler() { this.dispatchEvent(new CustomEvent('next')); } }
Die übergeordnete Komponente wartet auf das Ereignis mit dem Inline-Ereignis-Handler mit dem Präfix "on" (onnext).
<!-- todoApp.html --> <template> <c-todo-item onnext={nextHandler}></c-todo-item> </template>
Dieser übergibt das Ereignisobjekt an einen Ereignis-Handler.
// todoApp.js import { LightningElement } from 'lwc'; export default class TodoApp extends LightningElement { ... nextHandler(){ this.page = this.page + 1; } }
Übergeben von Informationen nach unten
Informationen können mithilfe von öffentlichen Eigenschaften und öffentlichen Methoden nach unten übergeben werden.
Sie können eine Komponenteneigenschaft öffentlich machen, indem Sie ihr den Decorator @api
voranstellen. Legen Sie dann die öffentliche Eigenschaft durch eine externe Komponente fest.
Beispielsweise (auch diese Komponenten sollten nicht erstellt werden), wenn die untergeordnete Komponente "c-todo-item" wie folgt definiert ist:
// todoItem.js import { LightningElement, api } from 'lwc'; export default class TodoItem extends LightningElement { @api itemName; }
Legen Sie den Wert aus der übergeordneten Komponente folgendermaßen fest:
<!-- todoApp.html --> <template> <c-todo-item item-name="Milk"></c-todo-item> </template>
Beachten Sie, dass die Variable itemName
unter Verwendung des mit Bindestrich geschriebenen Attributs item-name
festgelegt wird. Namen von Eigenschaften werden in JavaScript mit Binnenmajuskel notiert (Camel Case), während Attributnamen mit Bindestrichen (Kebab Case) notiert werden, um den HTML-Standards zu entsprechen. Das Attribut item-name
in Markup wird der JavaScript-Eigenschaft itemName
zugeordnet.
Öffentliche Eigenschaften sind eine hervorragende Lösung für das Übergeben primitiver Werte, einfacher Objekte und Arrays.
Ferner können Sie Getter und Setter verwenden, um Logik auszuführen, wenn Eigenschaften abgerufen oder festgelegt werden. Denken Sie ferner daran, sie mit dem Decorator @api
auszuzeichnen, um sie für andere Komponenten öffentlich zu machen.
Auf ähnliche Weise können Sie öffentliche Methoden erstellen, die von einer übergeordneten Komponente aus aufgerufen werden können. Erstellen Sie eine öffentliche Methode in der untergeordneten Komponente, indem Sie sie mit dem @api
-Decorator definieren, und rufen Sie sie dann von der übergeordneten Komponente aus auf.
Nehmen wir an, wir verfügen über eine untergeordnete Komponente wie diese (erstellen Sie diese Komponenten nicht).
// videoPlayer.js import { LightningElement, api } from 'lwc'; export default class VideoPlayer extends LightningElement { @api play() { // Play music! } }
Wenn die c-video-player-Komponente in einer übergeordneten Komponente enthalten ist, können wir die Methode wie folgt aus der übergeordneten Komponente aufrufen:
// methodCaller.js import { LightningElement } from 'lwc'; export default class MethodCaller extends LightningElement { handlePlay() { this.template.querySelector('c-video-player').play(); } }
Wir haben eine Methode handlePlay()
definiert, die das Ereignis auslöst. Dann verwenden wir die DOM-Methode querySelector()
, um nach einem DOM-Element namens c-video-player zu suchen und seine öffentliche Methode aufzurufen.
Verarbeiten von Ereignissen in HTML
Unsere Auswahlanwendung muss also in der Lage sein, eine Art von Ereignis zu verarbeiten – dass der Benutzer auf eine Kachel klickt. Wenn dies geschieht, sollte die Detailkomponente mit den Informationen aus der verknüpften Kachel neu gerendert werden. Sie können Ereignisse in HTML (fügen Sie der Vorlage einen Ereignis-Listener hinzu) oder JavaScript verarbeiten (schreiben Sie eine Ereignis-Listener-Funktion). Wir empfehlen, den HTML-Ansatz zu verwenden, wie hier zu sehen.
Jede Kachelkomponente lauscht auf Klicks des Benutzers, da der HTML-Code der Kachelkomponente (tile.html) einen onclick
-Ereignis-Listener enthält.
<template> <div class="container"> <a onclick={tileClick}> <div class="title">{product.fields.Name.value}</div> <img class="product-img" src={product.fields.Picture_URL__c.value} alt={product.fields.Name.value}/> </a> </div> </template>
Wenn ein Benutzer auf eine der Kachelinstanzen auf der Benutzeroberfläche klickt, ruft der onclick
-Listener die Handler-Funktion tileClick
in der JavaScript-Datei "tile.js" auf.
import { LightningElement, api } from 'lwc'; export default class Tile extends LightningElement { @api product; tileClick() { const event = new CustomEvent('tileclick', { // detail contains only primitives detail: this.product.fields.Id.value }); // Fire the event from c-tile this.dispatchEvent(event); } }
Ereignismuster der Auswahlanwendung
In unserer Produktauswahlanwendung verwenden wir eine komplexe Komponente (eine, die mehrere übergeordnete und untergeordnete Komponenten enthält). Es empfiehlt sich, das Ereignis durch die Hierarchie der Komponenten nach oben weiterzugeben, damit übergeordnete Komponenten auf untergeordnete Ereignisse reagieren können. Wenn Sie über weitere untergeordnete Komponenten verfügen (über diejenige hinaus, die das Ereignis auslöst), können Sie als Reaktion auf das Ereignis eine Eigenschaft nach unten an diese untergeordneten Komponenten übergeben.
Das Muster sieht wie folgt aus:
Hierzu müssen wir Ereignis-Listener und -Handler die Hierarchie aufwärts zur ebikes-Komponente verketten. Anschließend übergeben wir eine Eigenschaft abwärts zur Detailkomponente.
In unseren Dateien können Sie Folgendes sehen.
- "tile.html" verfügt über den
onclick
-Ereignis-Listener, der dentileClick
-Handler aufruft.
- "tile.js" enthält die
tileClick
-Methode, die ein neuesCustomEvent
mit dem Ereignistyptileclick
und ein Objekt erstellt, das einendetail
-Wert enthält (this.product.fields.Id.value
).
- "list.html" verfügt über den
ontileclick
-Listener, der denhandleTileClick
-Handler aufruft.
- "list.js" besitzt die Methode
handleTileClick
, die das Ereignis (evt
) übergibt, um ein weiteresCustomEvent
(productselected
) mit einem Objekt zu erstellen, das außerdem einendetail
-Wertevt.detail
enthält. Das Ereignis wird in JavaScript verteilt:// Fire the event from c-list this.dispatchEvent(event);
- "selector.html" besitzt den
onproductselected
-Ereignis-Listener, der denhandleProductSelected
-Handler aufruft.
- In "selector.js" legt die Methode
handleProductSelected
selectedProductId
auf den Wertevt.detail
fest, der ihr übergeben wurde. Die Variable "selectedProductId" wird von der Selektorkomponente an die Detailkomponente in "selector.html" übergeben:product-id={selectedProductId}
.
- "detail.html" verfügt über eine bedingte Anweisung (erinnern Sie sich daran noch aus Lektion 2?), die auf einen Produktwert wartet:
<template lwc:if={product}>
- "detail.js" führt die Teile zusammen. Sie erstellt eine private Variable
_productId
zur Nachverfolgung des Status des WertsproductId
. Anschließend verwendet sie ein get/set-Muster, um den Wert abzurufen und ihn auf eine Variableproduct
festzulegen, wodurch "detail.html" den bedingten Inhalt lädt.
Getter und Setter sind eine gängige JavaScript-Konstruktion. Sie ermöglichen es Ihnen, den Eigenschaftszuweisungen Logik und Bedingungen hinzuzufügen.
import { LightningElement, api } from 'lwc'; import { bikes } from 'c/data'; export default class Detail extends LightningElement { product; // Private var to track @api productId _productId = undefined; // Use set and get to process the value every time it's // requested while switching between products set productId(value) { this._productId = value; this.product = bikes.find(bike => bike.fields.Id.value === value); } // getter for productId @api get productId(){ return this._productId; } }
Jedes Mal, wenn Sie auf eine Kachel klicken, wiederholt sich dieser Vorgang.
Verteilen Ihrer Dateien in Ihrer Organisation
Lassen Sie uns diese neuen bikeCard-Projektdateien in Ihrer Organisation bereitstellen, um zu sehen, wie sie funktionieren. Verwenden Sie dieselben Schritte wie in der letzten Lektion, stellen Sie Ihre neuen Dateien bereit, öffnen Sie die Organisation und erstellen Sie eine Seite im Lightning-Anwendungsgenerator mit dieser Anwendung.
- Klicken Sie in VS Code im bikeCard-Projekt mit der rechten Maustaste auf den Ordner force-app/main/default und wählen Sie Folgendes aus: SFDX: Deploy Source to Org.
- Verwenden Sie in der Befehlspalette in VS Code SFDX: Open Default Org, um Ihre Organisation zu öffnen.
- Erstellen Sie eine Bereichsseite mithilfe der Auswahlkomponente.
- Geben Sie ihr die Bezeichnung
Your Bike Selection
(Ihre Fahrradauswahl).
- Ziehen Sie Ihre selector-Komponente ganz oben auf das Seitenlayout.
- Speichern Sie, und aktivieren Sie die Anwendung für alle Benutzer.
- Öffnen Sie die Anwendung, und sehen Sie Ihre funktionierende Komponente auf der Benutzeroberfläche.
Jetzt besitzen Sie eine vollständig interaktive Seite, die aus verschiedenen Komponenten zusammengesetzt ist, die zusammenarbeiten. Als Nächstes experimentieren wir mit der Gestaltung und dem Abruf von Live-Daten aus einer Organisation.
Ressourcen
- Entwicklerhandbuch für Lightning-Webkomponenten: Schatten-DOM
- Entwicklerhandbuch für Lightning-Webkomponenten: Kommunikation mit Ereignissen
- Entwicklerhandbuch für Lightning-Webkomponenten: Erstellen von Gettern und Settern