闪电Web组件基础

闪电Web组件基础 – 处理Lightning Web Components中的事件

学习目标

完成本单元后,您将能够:

  • 创建一个包含多个组件的应用程序。
  • 描述复杂组件的文件结构。
  • 处理事件。

跟随活动的旅程

您已经构建了一个组件并将其推送到临时组织。让我们开始添加一些与事件处理的交互性。我们通过几个组件跟踪事件的旅程,以在应用程序中进行复杂的事件处理。此应用程序是自行车商店的产品选择器。用户单击自行车名称和图像以查看更多详细信息。

自行车选择器组件。

这个程序有四个组件一起工作。

  1. tile:显示单个项目。
  2. list:排列瓷砖。
  3. detail:单击磁贴时显示项目详细信息(类似于您刚创建的bikeCard)。
  4. 选择器:包含整个组件集。容器组件不是必需的,但是我们在这里使用一个容器组件来帮助处理事件。

目前,该应用程序使用数据文件来加载静态数据以进行测试。在下一单元中,您将学习如何从组织中提取动态数据。

成分组成

让我们将一些文件添加到我们的项目中,然后将其部署到组织中。

  1. 在此处下载此应用程序的文件: Trailhead的Bike Selector应用程序
  2. 将文件解压缩到bikeCard项目的lwc文件夹中。自行车选择器应用程序文件结构。

组件关系

在此应用中,多个组件可以协同工作;一些组件嵌套在其他组件内部。正如您将HTML元素彼此嵌套一样,作为自定义HTML元素的Lightning Web组件也可以嵌套在其他Lightning Web组件内。

在我们的文件系统中,组件的文件夹实际上并不能深入了解它们之间的关系。

让我们看看图中的组件如何嵌套在UI级别上。

自行车选择器应用程序组件的父/子关系。

选择器组件对页面进行布局,并呈现列表和详细信息组件。list组件呈现了多个tile组件,数据中的每辆自行车一个。

<template>
    <div class="wrapper">
    <header class="header">Available Bikes</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>

如果您查看detail.html,则会看到条件渲染。如果未从列表中选择任何内容,那么将显示一条消息,要求用户选择某些内容。如果选择了某些内容,它将显示自行车信息。

<template>
    <template if:true={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}></img>
            <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 if:false={product}>
        <div>Select a bike</div>
    </template>
</template>

嵌套是在HTML中为每个父组件实现的。例如,list组件具有以下HTML,其中包括tile组件为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>

请注意,自行车项目的每次迭代如何生成新的图块组件。简单地包括c-tilecomponent标记即可使每个tile组件成为其子级。div类定义“容器”用于样式设置,因此您可以控制图块的排列。如果查看list.css,则会看到它包装了内容。

.container {
   display: flex;
   flex-direction: row;
   flex-wrap: wrap;
}

父子关系不仅对于应用程序的设计很重要,而且对于事件处理也很重要。

让我们更深入地了解事件处理。

事件增加,属性减少

在一个复杂的组件(一个包含多个父组件和子组件)中,这些组件可以上下通信。

父子组件上下传递信息。

  1. c-todo-item子组件将事件调度到父c-todo-app组件。例如,当用户单击按钮时,子级可以将事件对象传递给父级,以便父级可以处理事件并更改当前页面。
  2. c-todo-app父组件在子组件中传递属性或调用方法。例如,父级可以在子级组件中设置文本值,或在子级组件中调用方法。

让我们看看这种交流是如何工作的。

传递信息

可以使用事件和 事件侦听器传递信息 。

子组件调度事件,父组件监听事件。调度事件包括创建一个事件对象,孩子可以将该事件对象传递给父组件。父级具有处理程序以响应事件。

例如,像这样的子组件包含一个nextHandler()方法,该方法使用创建一个简单的事件对象,CustomEvent()并在用户单击“下一步”按钮时分派next值。

// todoItem.js
import { LightningElement } from 'lwc';
...
    nextHandler() {
        this.dispatchEvent(new CustomEvent('next'));
    }
}

父组件侦听该事件。

<!– todoApp.html -->
<template>
    <c-todo-item onnext={nextHandler}></c-child>
</template>

并将事件对象传递给事件处理程序。

// todoApp.js
import { LightningElement } from 'lwc';
export default class TodoApp extends LightningElement {
...
nextHandler(){
        this.page = this.page + 1;
    }
}

传递信息

可以使用公共属性和 公共方法来传递信息 。

您可以通过在@api装饰器前面添加组件属性来使其公开。然后,通过外部组件设置公共属性。

例如,如果c-todo-item子组件具有以下内容:

// todoItem.js
import { LightningElement, api } from 'lwc';
export default class TodoItem extends LightningElement {
   @api itemName;
}

使用以下命令设置父项的值:

<!– todoApp.html -->
<template>
    <c-todo-item item-name="Milk"></c-todo-item>
</template>

公共属性是传递原始值,简单对象和数组的绝佳解决方案。

另外,可以 在获取或设置属性时使用getter和setter来执行一些逻辑。并记住,用@api装饰器注释它们,以使其对其他组件公开。

同样,您可以创建可从父组件调用的公共方法。通过使用@api装饰器定义子组件,在子组件中创建一个公共方法,然后从父组件中调用它。

假设我们有一个像这样的子组件。

// videoPlayer.js
import { LightningElement, api } from 'lwc';
export default class VideoPlayer extends LightningElement {
   @api
   play() {
       // Play music!
   }
}

当c-video-player组件包含在父组件中时,我们可以像这样从父组件调用方法:

// methodCaller.js
import { LightningElement } from 'lwc';
export default class MethodCaller extends LightningElement {
   handlePlay() {
      this.template.querySelector('c-video-player').play();
   }
}

我们定义了一种handlePlay()触发事件的方法。然后,我们使用querySelector()DOM方法搜索名为c-video-player的DOM元素并调用其公共方法。

用HTML处理事件

因此,我们的选择器应用程序需要处理一种类型的事件-用户单击磁贴。发生这种情况时,详细信息组件应使用相关图块中的信息重新呈现。您可以处理HTML中的事件(在模板中添加事件侦听器)或JavaScript(编写事件侦听器函数)。我们建议使用HTML方法,如下所示。

每个图块组件都侦听用户单击,因为图块组件的HTML(tile.html)包含onclick事件侦听器。

<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}></img>
        </a>
    </div>
</template>

当用户单击UI中的一个tile实例时,onclick侦听器将调用tileClicktile.js JavaScript文件中的处理程序函数。

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);
    }
}

选择器应用程序事件模式

在产品选择器应用程序中,我们使用一个复杂的组件(一个组件包含多个父组件和子组件),建议您通过组件层次结构向上传播事件,以便父组件可以响应子事件。如果您还有其他子组件(而不是引发事件的子组件),则可以将属性传递给这些子组件以响应事件。

该模式如下所示:

事件流通过组件层次结构。

为此,我们需要将事件侦听器和处理程序按层次结构链接到ebikes组件。然后将一个属性传递到详细信息组件。

在我们的示例文件中,您将看到以下内容。

  1. tile.html具有onclick事件侦听器,该事件侦听器调用tileClick处理程序。
  2. tile.js具有tileClick创建包含细节值(this.product.fields.Id.value)的新CustomEvent对象的方法。
  3. List.html具有ontileClick调用handleTileClick处理程序的侦听器。
  4. List.js具有handleTileClick创建另一个evt也包含详细信息值的事件对象()的方法。并使用JavaScript调度事件:
    // Fire the event from c-list
    this.dispatchEvent(event);
  5. 选择器.html具有onproductselected调用handleProductSelected处理程序的事件侦听器。
  6. selector.js将handleProductSelected方法设置selectedProductId为该evt.detail值。
  7. detail.html具有等待产品值的条件指令(还记得单元2中的指令)吗:
    <template if:true={product}>
  8. detail.js将各个部分组合在一起。它创建一个私有variable _productId来跟踪productId值的状态。然后,它使用获取/设置模式获取值并将其设置为私有变量产品,该产品可以让detail.html加载条件内容。

Getter和Setter是常见的JavaScript结构。它们使您可以向属性分配添加逻辑和条件。

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;
    }
}

每次单击磁贴时,此过程都会重复进行。

注意

事件具有管理事件在DOM树上传播的属性。您可以在配置事件传播中了解有关它们的更多信息 。更改默认值是为了进行高级事件处理,并且需要进行测试以确保预期的行为。

将文件部署到组织

让我们将这些文件部署到启用了Dev Hub的组织中,以了解其工作原理。使用在上一个单元中执行的相同步骤,部署新文件,打开组织,并使用此应用程序在Lightning App Builder中创建页面。

  1. 要部署项目文件,请右键单击默认文件夹,然后选择SFDX:从VS Code中的命令面板中将源部署到组织
  2. 要打开您的组织,请使用SFDX:在VS Code中从命令面板打开默认组织
  3. 在设置中,在快速查找框中输入Lightning App Builder,然后选择Lightning App Builder
  4. 点击新建
  5. 使用选择器组件创建一个区域页面。

您将拥有一个完全交互式的页面,其中包含多个相互配合的组件。接下来,我们尝试样式化并从组织获取实时数据。

你可能也会喜欢...