适用于Aura开发人员的Lightning Web Components – 迁移JavaScript

学习目标

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

  • 将JavaScript从Aura组件迁移到Lightning Web组件。
  • 在Aura组件和Lightning Web组件之间共享代码。

使用JavaScript模块

JavaScript是Lightning Web组件的心脏。没有JavaScript,组件就是毫无生气的主要是HTML。当我们看到Aura组件中的属性如何映射到JavaScript属性时,我们可以窥见上一个单元中的Lightning Web组件中的JavaScript文件。现在,我们更深入地研究JavaScript文件。

将JavaScript代码从Aura组件中单独的客户端控制器,帮助程序和渲染器文件迁移到Lightning Web组件中的一个JavaScript文件。

Aura组件中的客户端控制器是对象文字表示形式的JavaScript对象,其中包含名称-值对的映射。好多话。让我们看一下PropertyPaginatorController.js文件中的示例:

({
	previousPage : function(component) {
        var pageChangeEvent = component.getEvent("pagePrevious");
        pageChangeEvent.fire();
	},
    
	nextPage : function(component) {
        var pageChangeEvent = component.getEvent("pageNext");
        pageChangeEvent.fire();
	}
})

Aura组件中JavaScript文件的格式是在将ES6标准(例如JavaScript类和模块)用于功能标准化之前设计的。

Lightning Web组件中的JavaScript文件是ES6模块,因此您使用的是标准JavaScript,而不是Aura组件中使用的专有格式。您编写的JavaScript看起来与您为其他任何现代JavaScript框架编写的JavaScript相似。

这是类似的JavaScript 分页器 闪电网络组件。

import { LightningElement, api } from 'lwc';
export default class Paginator extends LightningElement {
    /** The current page number. */
    @api pageNumber;
    /** The number of items on a page. */
    @api pageSize;
    /** The total number of items in the list. */
    @api totalItemCount;
    previousHandler() {
        this.dispatchEvent(new CustomEvent('previous'));
    }
    nextHandler() {
        this.dispatchEvent(new CustomEvent('next'));
    }
    get currentPageNumber() {
        return this.totalItemCount === 0 ? 0 : this.pageNumber;
    }
    get isFirstPage() {
        return this.pageNumber === 1;
    }
    get isLastPage() {
        return this.pageNumber >= this.totalPages;
    }
    get totalPages() {
        return Math.ceil(this.totalItemCount / this.pageSize);
    }
}

我们不会看每一行代码。主要的收获是Lightning Web组件使用标准的JavaScript模块。这是好事!

在Aura组件和Lightning Web组件之间共享代码

要在Lightning Web组件和Aura组件之间共享JavaScript代码,请将代码放在ES6模块中。两种编程模型都可以访问共享代码。即使您没有将所有代码都移至Lightning Web组件,您仍然可以访问在Aura组件的ES6模块中编写的新功能。

让我们看一个utils.js ES6模块的示例。

/* utils.js */
/**
 * Returns whether provided value is a function
 * @param {*} value - the value to be checked
 * @return {boolean} true if the value is a function, false otherwise
 */
export function isFunction(value) {
    return typeof value === 'function';
}

的 实用程序 模块导出一个 isFunction() 返回提供的参数是否为函数的函数。

这是一个 c-libcaller 使用以下内容的Lightning Web组件 实用程序 模块。

/* libcaller.js */
import { LightningElement } from 'lwc';
// import the library
import { isFunction } from 'c/utils';
export default class LibCaller extends LightningElement {
    result;
    
    checkType() {
        // Call the imported library function
        this.result = isFunction(
            function() {
                console.log('I am a function');
            }
        ); 
    }
}

的 c-libcaller 组件导入 实用程序 模块并调用 isFunction模块导出的函数。论点传递给isFunction 是一个函数,因此结果设置为 真正

现在,让我们看一个libcallerAura.cmp文件,该文件也使用实用程序 模块。

<aura:component>
    <aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
    <p>Aura component calling the utils lib</p>
    <!-- add the lib component -->
    <c:utils aura:id="utils" />
</aura:component>

的 libcaller光环 光环组件包括对 c:工具ES6模块。我们添加了一个光环:id 这样我们就可以在JavaScript代码中获得对该模块的引用。

这是libcallerAuraController.js文件。

({
    doInit: function(cmp) {
        // Call the lib here
        var libCmp = cmp.find('utils');
        var result = libCmp.isFunction(
            function() {
                console.log(" I am a function");
            }
        );
        console.log("Is it a function?: " + result);
    }
})

组件的控制器使用 cmp.find(’utils’) 匹配 光环:id在标记中并获得对该模块的引用。的实用程序 ES6模块导出 isFunction(),由Aura组件调用。论点传递给isFunction() 是一个函数,因此结果设置为 真正

使用第三方JavaScript库

要在Aura组件或Lightning Web组件中使用第三方JavaScript库,必须将库作为静态资源上载。在两种编程模型中,使用静态资源的语法不同。

在Aura组件中,使用 <ltng:require> 在标记中添加标签以加载静态资源。

<ltng:require scripts="{!$Resource.resourceName}"
    afterScriptsLoaded="{!c.afterScriptsLoaded}" />

resourceName是静态资源的名称。的afterScripts已加载 加载脚本并呈现组件后,将调用客户端控制器中的action。

在Lightning Web组件中,使用JavaScript导入静态资源。

import resourceName from '@salesforce/resourceUrl/resourceName';

然后,您使用 loadScript 和 loadStyle 加载第三方库。

有关使用导入的库的详细信息,请参阅《 Lightning Web Components开发人员指南》中的“使用第三方JavaScript库

动态创建组件

在Aura组件中,您可以使用以下方式在JavaScript中动态创建组件: $ A.createComponent()。在Lightning Web组件中没有动态创建组件的等效项。

这个体系结构的决定是有意的。不在Lightning Web组件中复制此模式的主要原因是Aura组件中的模式导致错误和混乱的代码。

Lightning Web组件中更好的替代方法是为您的组件创建多个HTML模板。组件的render()该方法可以根据组件需求切换模板。这种模式更类似于其他JavaScript框架中使用的路由拆分。

重构的机会

迁移JavaScript代码时,请注意,它不是逐行转换。这是重新审视组件设计的好机会。

迁移到新的编程模型就像走一条新路径,将您带到相同的目的地。一路上的视觉和声音(以及您编写的代码)是不同的。

迁移组件也是使用Aura组件中可能未使用的ES6新功能(例如JavaScript模块)的绝佳机会。

在现代JavaScript开发的Trailhead模块为您提供了这些新功能很好的概述。

适用于Aura开发人员的Lightning Web Components – 迁移标记和CSS

学习目标

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

  • 将HTML和标记从Aura组件迁移到Lightning Web组件。
  • 将CSS从Aura组件迁移到Lightning Web组件。

梦之屋应用

比较Aura Component和Lightning Web Components编程模型的最佳方法是查看两个模型中编写的相似组件的代码。

我们将研究DreamHouse应用程序中的某些组件,该应用程序是Salesforce开发来展示Lightning组件的相对复杂的应用程序。DreamHouse是一个基于Salesforce平台的房地产业务的示例应用程序。该应用程序使经纪人能够管理其财产,并使买家能够找到他们梦想中的家。

DreamHouse应用程序具有针对Aura组件和Lightning Web组件的单独实现,并且每个组件的完整代码都位于两个不同的GitHub存储库中。在两个版本的应用程序中,功能都不相同,但是有一些组件可用于比较两个编程模型。

GitHub存储库中提供了DreamHouse应用程序的两种实现的代码。

  • DreamHouse Aura组件GitHub存储库
  • DreamHouse Lightning Web组件GitHub存储库

我们将查看Aura组件中的代码片段,并向您展示Aura代码如何映射到Lightning Web组件代码。我们还将向您展示Aura组件概念如何转换为Lightning Web组件,并且我们将重点关注核心片段以说明这些概念。然后,如果您对更多上下文感兴趣,可以探索这些组件。

组件捆绑

对于Aura组件和Lightning Web组件,组件捆绑包文件结构不同。这是文件在两种类型的组件之间的映射方式。

资源资源 光环文件 闪电Web组件文件
标记 sample.cmp sample.html
控制者 sampleController.js sample.js
帮手 sampleHelper.js
渲染器 sampleRenderer.js
的CSS sample.css sample.css
文献资料 sample.auradoc 目前不可用
设计 样本设计 sample.js-meta.xml
SVG sample.svg 包含在HTML文件中或作为静态资源上传

注意

Aura组件中的单独的控制器,助手和渲染器文件映射到Lightning Web组件中的一个JavaScript文件。

Lightning Web组件必须包含HTML文件,JavaScript文件和配置文件。它可以选择包括CSS文件和更多JavaScript文件。

不呈现任何UI的组件(也称为服务组件或库)必须包含JavaScript文件和元数据配置文件。

在本单元中,我们研究HTML和CSS文件。在下一单元中,我们探索JavaScript文件。

Lightning Web组件还具有一个配置文件,该文件定义了该组件的元数据值,包括打算在Lightning App Builder中使用的组件的设计配置。配置文件中包含一些由接口定义的元数据,例如flexipage:availableForRecordHome,在Aura组件中。

迁移标记

Aura组件在.cmp文件中包含标记。该文件以 <光环:组件> 标签,并且可以包含HTML和Aura特定的标签。

Lightning Web组件在.html文件中包含标记。该文件以<模板> 标签,并且可以包含HTML和动态内容的指令。

让我们看看Aura标记如何映射到Lightning Web组件的HTML和JavaScript文件中的内容。

属性成为JavaScript属性

从迁移属性 <光环:属性>将Aura组件的标记(.cmp)中的标签添加到Lightning Web组件的JavaScript文件(.js)中的JavaScript属性。

让我们在标记的属性中查看这些属性 物业摘要灵气成分。您可以在DreamHouse Aura组件GitHub存储库中看到完整的文件。

    <aura:attribute name="recordId" type="Id" />
    <aura:attribute name="property" type="Property__c" />

在Lightning Web组件中,我们使用JavaScript属性而不是标记中的属性。让我们看一下propertySummary.js中的属性

import { LightningElement, api } from 'lwc';
export default class PropertySummary extends LightningElement {
    @api recordId;
    property;
        ...
}

的 recordId 和 属性 灵气成分的属性变为 recordId 和 属性 Lightning Web组件中的JavaScript属性。

的 @api 装饰标记 recordId作为公共财产。公共属性是该组件的公共API的一部分,这意味着可以在Lightning App Builder中对其进行设置,也可以由在其标记中使用该组件的父组件来对其进行设置。

基本的Aura表达式成为HTML表达式

将基本表达式从Aura组件中的标记迁移到Lightning Web组件中的HTML表达式。基本表达式的一个示例是对Aura组件中的属性的引用。

例如, PropertyPaginator Aura组件使用基本表达式来显示 , 页数和  属性。

<aura:component >
    <aura:attribute name="page" type="integer"/>
    <aura:attribute name="pages" type="integer"/>
    <aura:attribute name="total" type="integer"/>
    
    <div class="centered">{!v.total} properties • page {!v.page} of {!v.pages}</div>
</aura:component>

这是HTML文件中的等效语法 分页器 闪电网络组件。

<template>
    {totalItemCount} items • page {currentPageNumber} of {totalPages}
</template>

注意

Lightning Web组件的HTML文件中的动态内容没有感叹号或值提供程序(v。) 句法。即使可能会用手指打字,也不要在Lightning Web组件中使用Aura组件中的表达式语法!

HTML引用了 totalItemCountpaginator.js中的属性。的{currentPageNumber} 和 {totalPages} 表达式引用处理程序的吸气剂 pageNumber 和 页面大小 属性。

import { LightningElement, api } from 'lwc';
export default class Paginator extends LightningElement {
    /** The current page number. */
    @api pageNumber;
    /** The number of items on a page. */
    @api pageSize;
    /** The total number of items in the list. */
    @api totalItemCount;
    get currentPageNumber() {
        return this.totalItemCount === 0 ? 0 : this.pageNumber;
    }
    get totalPages() {
        return Math.ceil(this.totalItemCount / this.pageSize);
    }
}

了解条件语句后,我们会尽快处理更复杂的表达式。

Aura条件句成为HTML条件句

迁移 <光环:如果> Aura组件中的标签 如果属实 要么 如果:假 Lightning Web组件的HTML文件中的指令。

这是一些条件标记 经纪人详细信息 灵气成分。

<aura:if isTrue="{!v.property.Broker__c}">
    <lightning:recordForm recordId="{!v.property.Broker__c}"
      objectApiName="Broker__c"
      fields="{!v.brokerFields}" columns="2"/>
</aura:if>

这是类似的HTML brokerCard 闪电网络组件。

<template if:true={property.data}>
    <lightning-record-form object-api-name="Broker__c" 
      record-id={brokerId} fields={brokerFields} 
      columns="2">
    </lightning-record-form>
</template>

注意

Lightning Web组件的HTML文件中的动态内容没有引号, {brokerId}参考。这不是错字!

Lightning Web组件的HTML文件以标准HTML开头 <模板> 标签,并且还可以包含其他 <模板>标签在其体内。在此示例中, <模板> 标签会根据 如果属实 指示。

复杂的Aura表达式成为JavaScript逻辑

我们看到了基本的Aura表达式,例如对属性值的引用,如何变成HTML表达式。将Aura组件中的复杂Aura表达式(例如比较运算或三元运算符)迁移到Lightning Web组件中的JavaScript getter。

Aura组件支持丰富的表达式集,例如 PropertyPaginator Aura组件,它使用 {!v.page> 1}

<aura:if isTrue="{!v.page > 1}">
    <lightning:buttonIcon iconName="utility:left" variant="border" onclick="{!c.previousPage}"/>
</aura:if>

Aura中的表达语言使您可以在标记中包含更多逻辑。不利之处在于,很难对该逻辑进行单元测试,并且该功能只是您在JavaScript中可以执行的操作的一部分。

在Lightning Web组件中,将复杂表达式移动到JavaScript中。现在可以对代码进行单元测试,这使代码更稳定,开发人员更快乐。您还可以使用JavaScript的全部功能来编写逻辑。

这是类似的HTML 分页器 闪电网络组件。

<template if:false={isFirstPage}>
    <lightning-button-icon icon-name="utility:chevronleft" onclick={previousHandler}></lightning-button-icon>
</template>

paginator.js中的getter计算{isFirstPage}健康)状况。例如:

import { LightningElement, api } from 'lwc';
export default class Paginator extends LightningElement {
    /** The current page number. */
    @api pageNumber;
    get isFirstPage() {
        return this.pageNumber === 1;
    }
}

Aura迭代成为HTML迭代

迁移 <光环:迭代> Aura组件中的标签 为:每个 Lightning Web组件的HTML文件中的指令。

这是PropertyTileList.cmp中的Aura语法。

<aura:iteration items="{!v.properties}" var="property">
    <c:PropertyTile property="{#property}"/>
</aura:iteration>

这是类似的HTML propertyTileList 闪电网络组件。

<template for:each={properties.data.records} for:item="property">
    <c-property-tile property={property} key={property.Id} 
      onselected={handlePropertySelected}></c-property-tile>
</template>

Aura初始化程序成为生命周期挂钩

更换 在里面 具有标准JavaScript的Aura组件中的事件处理程序 connectedCallback()Web组件中的方法。的connectedCallback() 将组件插入DOM时会触发生命周期挂钩。生命周期挂钩是回调方法,使您可以在组件生命周期的每个阶段运行代码。

我们使用 在里面 Aura组件中的事件用于在组件构造之后但渲染之前初始化组件。

这是一个 在里面 中的事件处理程序 物业轮播 灵气成分。

<aura:handler name="init" value="{!this}" action="{!c.onInit}" />

的 onInit Aura组件的控制器中的函数执行任何必要的初始化。

在Lightning Web组件中,使用 connectedCallback() 而是在组件的JavaScript文件中。这是propertySummary.js中的示例 。

export default class PropertySummary extends LightningElement {
    ...
    connectedCallback() {
        // initialize component
    }
}

迁移基础组件

还记得Lightning Web组件不能包含Aura组件吗?如果您需要迁移的Aura组件包含Salesforce提供的内置组件,该怎么办?基础闪电组件是Salesforce在闪电名称空间,它们在Aura组件和Lightning Web组件中都可用。在两个编程模型中使用基础Lightning组件时,它们具有不同的语法。

此光环组件使用 闪电:formattedNumber 基本组件。

<aura:component>
    <lightning:formattedNumber value="5000" style="currency"
      currencyCode="USD" />
</aura:component>

将此标记迁移到Lightning Web组件:

  • 更改用于分隔名称空间的冒号(闪电)和组件名称(formattedNumber)。
  • 更改驼峰案例的组件名称(formattedNumber)以短划线分隔的名称(格式化数字)。
  • 更改驼峰案例属性名称(货币代码)以短划线分隔的名称(货币代码)。

这是等效的Lightning Web组件。

<template>
    <lightning-formatted-number value="5000" style="currency"
      currency-code="USD">
    </lightning-formatted-number>
</template>

注意

HTML规范要求自定义元素的标签不能自动关闭。自闭合标签以/>。Lightning Web组件本质上是一个自定义元素。因此,<闪电格式编号> 组件参考包含一个单独的结束语 </ lightning-formatted-number>标签。此要求与允许自动关闭标签的Aura组件不同。

Aura CSS成为标准CSS

闪电Web组件使用标准CSS语法。删除专有这个 Aura组件使用的类。

这是CSS文件的一部分, PropertyTile 灵气成分。

.THIS .lower-third {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    color: #FFF;
    background-color: rgba(0, 0, 0, .3);
    padding: 6px 8px;
}
.THIS .lower-third > p {
    padding: 0;
    margin: 0;
}
.THIS .truncate {
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

类似的CSS propertyTileLightning Web组件改用标准CSS。的这个 关键字特定于Aura,在Lightning Web组件中未使用。

.lower-third {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    color: #FFF;
    background-color: rgba(0, 0, 0, .3);
    padding: 6px 8px;
}
.lower-third > p {
    padding: 0;
    margin: 0;
}
.truncate {
  width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

带有闪电设计系统的样式组件

Lightning Experience或Salesforce移动应用程序中的自定义组件可以使用Lightning Design System,而无需任何导入语句或静态资源。将Lightning Design System CSS类分配给HTML元素,就可以了。

闪电Web组件继承Aura组件样式

Aura组件样式可级联到它们包含的任何Lightning Web组件。

但是,Lightning Web组件的样式永远不会干扰其他Lightning Web组件或Aura组件。是的,你没看错。闪电Web组件样式不会与其子级联。您不拥有的覆盖样式会造成很多问题,因此Lightning Web组件不允许这样做。

Shadow DOM的CSS封装

闪电Web组件使用一种称为阴影DOM的Web标准机制,该机制从包含该组件的页面中隐藏该组件内的元素。由于Lightning Web组件具有阴影DOM,因此在组件样式表中定义的样式将限于该组件。它们不适用于父,子或同级组件。此规则很严格,但是它允许在不同的上下文中重用组件而不会丢失其样式。它还可以防止组件的样式覆盖页面其他部分中的样式。

为了使组件作者更容易开发,Lightning Web组件的影子DOM的工作原理与Web标准有所不同。区别在于,Lightning Web组件的阴影DOM是自动创建的。组件作者不必实现它。此外,即使在本机不支持影子DOM的浏览器上,Lightning Web组件的影子DOM也可以使用。

适用于Aura开发人员的Lightning Web Components – 了解闪电Web组件如何与Aura组件一起使用

学习目标

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

  • 列出Lightning Web组件的优点。
  • 描述Aura组件和Lightning Web组件如何协同工作。
  • 确定何时迁移组件。

一种新的编程模型

您现在可以在两种编程模型中开发Lightning组件:原始模型(Aura组件)和新模型(Lightning Web组件)。就在您掌握了Aura组件的开发之后,我们就提供了Lightning Web组件!为什么,哦为什么,你问?好吧,我们创建了Lightning Web Components模型来与几年前建立原始Aura模型时不存在的Web标准保持一致。

注意

您是否注意到最后一段中的大写字母不同?如果是这样,您有敏锐的眼睛。当我们引用Lightning Web Components编程模型时,所有单词都大写。仅当我们将组件本身称为Lightning Web组件时,才大写第一个单词。

同样,您一直在使用的编程模型现在称为Aura Components编程模型,您可以创建Aura组件。

为了说明这一点,您在Lightning Web Components编程模型中创建了Lightning Web组件。在“ Aura组件”编程模型中,创建Aura组件。

本模块的目的是帮助您利用Aura组件的技能来加快对Lightning Web组件的了解。您将了解两种类型的组件如何在同一个应用程序中协同工作。

什么是闪电Web组件?

Lightning Web Components是W3C的Web Components标准的实现。它支持Web组件在浏览器中运行良好的部分,并且仅添加在Salesforce支持的所有浏览器中工作所需的内容。

闪电Web组件的好处是什么?

现代JavaScript
在过去的几年中,具有ES6 +和Web标准的JavaScript语言(例如HTML模板,自定义元素和Web组件)已经有了很大的发展。Lightning Web Components为Lightning Component框架带来了现代的JavaScript和Web标准。
开发人员的生产力和满意度
学习如何更快地构建Lightning Web组件,因为您正在使用标准的JavaScript,HTML和CSS。有专有组件和API,可以更轻松地使用Salesforce,但是您可以通过标准方式访问和使用这些专有组件。
使用Lightning Web组件编写更少的代码,并且这些代码更易于阅读,维护和单元测试。
通过转到您喜欢的搜索引擎,可以更轻松地找到您的开发问题的答案。使用Web标准可以加快开发和调试时间。
使用您喜欢的开发工具,因为Lightning Web组件使用标准的JavaScript并可以与您选择的工具很好地配合使用。
代码性能
使用Web标准可以提高性能,因为更多功能是由浏览器而不是JavaScript框架本地执行的。根据使用情况的不同,这种改进可能会有所不同,但是我们相信您会为组件的更快的渲染时间感到惊喜。

先决条件

在深入学习此模块之前,请完成Lightning Web Components基础知识模块,该模块为您提供了对新编程模型的出色介绍。

我们假设您熟悉Aura Components编程模型,除了与Lightning Web Components编程模型相比,我们不会解释其功能。如果您不熟悉Aura组件,请从“ Aura组件基础知识”模块开始。

您还需要了解现代JavaScript开发和ES6 JavaScript功能。如果这些术语令人困惑,则可以在Modern JavaScript Development模块中了解它们。该模块涵盖了开发Lightning Web组件所需的所有JavaScript技能。

带扣旅行

学习任何新的编程模型或语言都是一段旅程。当您运行一些新代码时,就像在开阔的道路上驾驶敞篷车时的快感。然后,您更改一行代码,然后得到一个错误。您猛踩刹车,但遇到交通拥堵,拼命寻找下一个出口。记住,这是一个旅程。错误只是暂时的减速,您最终会到达目的地……希望在晚餐时间之前。

我们希望该模块为您的Lightning Web组件之旅做好准备。可以将模块视为打包旅行的行李箱。我们会逐步引导您完成冒险所需的一切。当您到达目的地时,我们不希望您打开行李箱并意识到您忘了打包内衣了!

组件生活在一起

让我们开始看看如何将组件组合在一起。您可以在另一个组件的主体内添加组件。这种组件组成使您可以从更简单的构建块组件中构建复杂的组件。组件组成的概念对于Aura组件和Lightning Web组件都是至关重要的。

我们知道您可能在开发Aura组件上投入了大量时间和精力。因此,我们投入了时间,使您能够在同一应用程序中组合Aura组件和Lightning Web组件。例如,您可以编写一个新的Lightning Web组件并将其添加到包含Aura组件的应用程序中。

除了将Aura组件和Lightning Web组件组合在一起之外,这两种类型的组件还可以与事件进行通信。这是一种健康的共存。

像任何关系一样,有一些规则可以确保所组成的组件一起良好地工作。

重要

允许的Aura组件 可以包含Lightning Web组件。

不允许 闪电Web组件不能包含Aura组件。

如果您要构建一个Lightning Web组件,并且其主体中还需要其他子组件,则这些子组件也必须作为Lightning Web组件构建。请记住,Lightning Web组件不能包含Aura组件。

如果Lightning Web组件是嵌套组件树中最外面的组件,则任何嵌套组件都不能是Aura组件。

两种编程模型一起工作的优点之一是,您可以决定将一个Aura组件迁移到Lightning Web组件,然后您的应用程序继续运行。即使您决定将Lightning Web组件用于新组件,您仍然可以利用对Aura组件的任何现有投资。

另外,您可以在ES6模块中编写新代码,并从Lightning Web组件和Aura组件访问该代码。这种模式为Aura开发人员打开了现代JavaScript开发的大门。

迁移策略

迁移代码很少是一条直线路。Lightning Web Components的编程模型与Aura Components的模型根本不同。将Aura组件迁移到Lightning Web组件不是逐行转换,这是重新访问组件设计的好机会。在迁移Aura组件之前,请评估该组件的属性,接口,结构,模式和数据流。

最容易迁移的组件是仅呈现UI的简单组件。性能至关重要的Aura组件很适合迁移到Lightning Web组件。

通过迁移更大的组件树(组件内的组件)而不是单个组件,可以在性能和开发人员生产率上获得更多收益。但是,迁移一个组件并查看Aura编程模型中的概念如何映射到Lightning Web Components编程模型中的概念是非常有用的学习经验。

迁移一个组件之后,您将可以更好地确定对您和您的组织是否有意义:

  • 进行更大的迁移工作。
  • 仅将Lightning Web组件用于新组件。
  • 暂时使用Aura组件。

选择权取决于您,每个人的选择都不同,具体取决于用例和可用资源。无论您做出什么决定,迁移组件都是一项有价值的学习活动。

闪电Web组件和Salesforce数据 – 处理服务器错误

学习目标

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

  • 说明连接属性时如何处理服务器错误。
  • 说明如何处理在连接功能时发生的服务器错误。
  • 说明如何处理在调用LDS函数或强制性Apex时发生的服务器错误。
  • 确定推荐的与数据交互并处理特定用例错误的方式。

处理闪电Web组件中的服务器错误

LDS线适配器,LDS功能和对Apex的调用引发的错误具有特定的结构。要检索有关错误的信息,请在JavaScript代码中处理错误响应。然后,您可以向用户显示错误的内容。

作为开发人员,您可以决定如何向用户显示错误:错误面板,祝酒消息或其他内容。出于学习目的,此模块中的示例通过引用errors标记中的属性来显示错误,如下所示:

errors.html

<template>
    <template if:true={errors}>
        <p>{errors}</p>
    </template>
</template>

如何使用JavaScript处理服务器错误取决于您如何交互Salesforce数据。让我们探索三个示例:有线属性,有线功能和命令式调用。

处理连线属性错误

当您使用@wire装饰的属性,错误是在属性访问error属性。当@wire与LDS线适配器或Apex一起使用时,此设置有效 。

wireApexProperty.js

import { LightningElement, api, wire } from 'lwc';
import { reduceErrors } from 'c/ldsUtils';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class WireApexProperty extends LightningElement {
    @api recordId;
    @wire(getRelatedContacts, { accountId: '$recordId' })
    contacts;
    get errors() {
        return (this.contacts.error) ?
            reduceErrors(this.contacts.error) : [];
    }
}

代码重点:

  • 第2行:我们reduceErrors 从ldsUtils模块导入了 辅助函数。(您ldsUtils稍后将在本单元中将模块添加 到项目中。)
  • 第6-7行:装饰contacts属性以 @wire将其连接到 getRelatedContacts函数。
  • 第8行:我们定义了一个getter函数,该函数创建一个名为的属性 errors。每次this.contacts.error更改时,getter都会更新errors属性的值。发生这种情况是由于 反应性
  • 第10行:在getter中,我们使用reduceErrorshelper函数来格式化this.contacts.error。该函数将减少接收到的错误对象,并返回所有已发生错误消息的数组。

注意

reduceErrors本示例中 的帮助器功能来自LWC Recipes 示例应用程序的ldsUtils模块 。LWC食谱包含以Lightning Web组件实现的常见模式的简单易懂的示例。随时将模块复制到您的项目中,然后使用该功能。 ldsUtilsreduceErrors

处理有线功能上的错误

当使用@wire装饰的函数,该函数作为参数接收的对象,其包括错误(如果有任何错误)。当@wire与LDS线适配器或Apex一起使用时,这适用。

wireApexFunction.js

import { LightningElement, api, wire } from 'lwc';
import { reduceErrors } from 'c/ldsUtils';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class WireApexFunction extends LightningElement {
    @api recordId;
    errors;
    @wire(getRelatedContacts, { accountId: '$recordId' })
    wiredContacts({data, error}) {
        if (error)
            this.errors = reduceErrors(error);
    }
}

代码重点:

  • 第2行:我们reduceErrorsldsUtils模块中导入了辅助函数 (就像在wireApexProperty示例中所做的那样)。
  • 第三行:我们getRelatedContactsAccountController类中导入函数 。
  • 第6行:我们定义errors属性。
  • 第7–8行:装饰wiredContacts函数以 @wire将其连接到 getRelatedContacts函数。
  • 第10行:每次有线函数接收到错误时,我们都会使用 reduceErrorshelper函数对其进行格式化。该函数返回所有已发生错误的数组。

强制调用函数时的错误处理

如果必须强制调用LDS函数或Apex方法,则服务器会将错误作为参数返回到catch方法的回调函数。

callApexImperative.js

import { LightningElement, api, wire } from 'lwc';
import { reduceErrors } from 'c/ldsUtils';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class CallApexImperative extends LightningElement {
    @api recordId;
    errors;
    handleButtonClick() {
        getRelatedContacts({
            accountId: '$recordId'
        })
            .then(contacts => {
                // code to execute if the promise is resolved
            })
            .catch(error => {
                this.errors = reduceErrors(error); // code to execute if the promise is rejected
            });
    }
}

代码重点:

  • 第2行:我们导入了reduceErrors辅助函数。
  • 第6行:我们定义了一个名为的属性errors
  • 第8行:我们getRelatedContacts强制调用该函数。该函数返回一个promise。
  • 第11-13行:如果诺言得以兑现,我们将进行处理contacts
  • 第14-16行:如果承诺被拒绝,我们将使用 reduceErrorshelper函数来格式化接收到的错误并将其存储在errors属性中。

处理accountList组件中的错误

让我们向您创建的accountList组件添加错误处理。

  1. 在accountList.html文件中,在<template>包括的lightning-datatable之后添加以下代码:
    <template if:true={errors}>
        <p>{errors}</p>
    </template>
  2. ldsUtilsLWC配方中 复制组件, 并将其包含在项目的force-app / main / default / lwc文件夹中。该组件包含 reduceErrors功能。
  3. reduceErrorsaccountList.js开头附近导入函数。
    import { reduceErrors } from 'c/ldsUtils';
  4. 在accountList.js中,插入此getter,它定义了一个 errors属性:
    get errors() {
        return (this.accounts.error) ?
            reduceErrors(this.accounts.error) : [];
    }
  5. 要测试错误处理,getAccounts通过注释方法的主体(临时)并在此位置添加以下代码来强制方法(在AccountController.cls中)引发错误:
    throw new AuraHandledException('Forced error');
  6. 保存您编辑的三个文件:accountList.html,accountList.js和AccountController.cls。
  7. 部署项目文件(来自force-app/main/default)。
  8. 如果尚未打开,请打开您的Trailhead Playground。
  9. 要检查结果,请刷新“使用数据”页面。
    提示:由于Lightning Data Service缓存结果,因此您可能需要清除缓存,然后才能看到强制错误在起作用。

概要

现在,您知道了与Lightning Web组件中的Salesforce数据进行交互的几种方法。在某些情况下,某些解决方案优于其他解决方案。下表按用例总结了推荐的解决方案。

与Salesforce数据进行交互的用例

用例 推荐的解决方案 笔记
查看或编辑指定其布局或字段列表的记录 lightning-record-form
使用自定义表单布局或记录数据的自定义呈现方式查看记录 lightning-record-view-form
使用自定义表单布局,自定义记录数据呈现或预填充字段值来编辑记录 lightning-record-edit-form
读取元数据或读取一条记录的数据 LDS电线适配器 可以合并,但操作将在独立事务上运行
创建,编辑或删除一条记录 LDS功能 可以合并,但操作将在独立事务上运行
读取多条记录 致电Apex @wire 使用以下注释Apex方法 cacheable=true
一次性读取多个记录或修改多个记录 必须致电Apex 对于读取,请使用以下注释Apex方法 cacheable=true

当您在Lightning Web组件中使用数据时,错误处理会有所不同。您如何访问错误取决于您如何与数据进行交互。

处理服务器错误

如何处理数据 如何访问服务器错误
使用LDS线适配器或Apex方法,并装饰属性 使用reduceErrors来处理所返回的有线财产的错误decoratedProperty.error
使用LDS线适配器或Apex方法,并装饰功能 使用reduceErrors来处理在通过有线功能接收对象参数返回错误

decoratedFunction({data, error}) {...}

强制调用LDS连线函数或Apex方法 使用reduceErrors来处理真实收到的捕捞方法的回调函数中的参数错误

functionToInvoke()
.then(data => {...})
.catch(error => {...});

包起来

在本模块中,您了解了在Lightning Web组件中使用Salesforce数据的不同方法。您了解了每种技术的优缺点,何时推荐每种技术以及如何实现每种解决方案。您还根据与Salesforce数据的交互方式学习了如何处理Lightning Web组件中的服务器错误。

要继续了解有关在Lightning Web组件中使用Salesforce数据的知识,请查看此模块中提供的资源。另外,请参阅《 快速入门:探索食谱示例应用程序》, 以获取更多示例和实现它们的代码。

闪电Web组件和Salesforce数据 – 使用Apex处理数据

学习目标

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

  • 识别何时需要使用Apex处理Salesforce数据。
  • 用两种不同的方式呼叫Apex。
  • 使用Apex和lightning-datatable处理记录列表。

闪电Web组件中的Apex

我们已经介绍了Lightning Data Service的好处以及如何使用它,但是有时,lightning-record-*-form组件或LDS线适配器和功能都不适合特定的用例。例如,当您要自定义单记录数据事务或对单个事务执行多记录操作时,Apex是最佳选择。

将Apex方法与Lightning Web Components一起使用

在闪电网络组件使用的顶点方法必须是static, public或者global,并用注释 @AuraEnabled立即方法定义之前。该 @AuraEnabled注释使其可闪电部件(两个闪电Web组件和Aura组件)的顶点方法。

允许框架缓存数据可消除重复的服务器调用,从而使以后的读取操作运行更快。通过cacheable = true@AuraEnabled批注中进行设置,我们将方法标记为可缓存 。当@AuraEnabled方法是可缓存的时,不允许进行数据操作语言(DML)操作。在此示例的第2行中,我们使getRelatedContacts方法可缓存。

AccountController.cls

public with sharing class AccountController {
    @AuraEnabled(cacheable=true)
    public static List<Contact> getRelatedContacts(Id accountId) {
        return [
            SELECT Name, Title, Email, Phone
            FROM Contact
            WHERE AccountId = :accountId
            WITH SECURITY_ENFORCED
       ];
    }
}

当方法是可缓存的时,直到刷新缓存后,才会返回新添加或更改的记录版本。在下一节中了解如何手动刷新缓存。

从LWC调用Apex方法

与Lightning Web组件中的Apex方法进行交互的方法有两种:连接方法或强制调用方法。让我们考虑两种方法。

使用@wire致电Apex

要连接Apex方法,该方法必须是可缓存的。要连线可缓存的Apex方法,请使用@wire装饰器(与使用LDS连线适配器的方式相同)。以这种方式调用Apex会将控件委派给Lightning Web Components引擎并创建响应式服务。每次传递给Apex方法的参数值更改时,Apex方法都会将新值提供给修饰的属性或函数。由于有线方法必须是可缓存的,因此数据可以来自LDS缓存或服务器。要刷新Apex方法缓存的数据,请调用 refreshApex 函数。

注意: Lightning Data Service无法识别Apex方法缓存的数据。当LDS函数更新记录时,该更新对Apex方法缓存的数据没有影响。

这是@wire用于调用Apex的示例。此代码获取帐户的相关联系人。

wireApexProperty.js

import { LightningElement, api, wire } from 'lwc';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class WireApexProperty extends LightningElement {
    @api recordId;
    @wire(getRelatedContacts, { accountId: '$recordId' })
    contacts;
}

代码重点:

  • 第2行:我们getRelatedContactsAccountControllerApex类导入函数 。这指向相应的Apex方法。
  • 第4行:我们定义了一个@api recordId属性,以便FlexiPage将当前记录的ID传递给组件。
  • 第5行:@wire装饰器收到两个参数:我们要调用的Apex方法(getRelatedContacts)和适配器需要的参数(accountId)。我们将其$recordId作为反应变量传递 (以开头 $)。
  • 第6行:结果存储在contacts属性中。
  • 第5至6行:最初,Apex方法将数据置备给 contacts属性,并将该数据存储在LDS缓存中。由于$recordId是反应型的,因此每次其值更改时,Apex方法都会从缓存或服务器中配置新数据。

紧急呼叫Apex

调用Apex的另一种方法@wire是强制性地调用Apex。当您需要控制读取操作的调用以及修改记录时,必须强制调用Apex。要强制调用Apex,请一次从组件的JavaScript文件中调用Apex,而不是将控件委派给Lightning Web Components引擎。作为回报,您将获得JavaScript承诺(就像您必须强制调用LDS函数时所做的那样)。

您可以强制调用可缓存和不可缓存的Apex方法。要刷新可缓存方法的缓存,请再次调用该方法。

在callApexImperative.js示例中,当用户单击 lightning-button.html文件(未显示)中的a时, handleButtonClickgetRelatedContacts强制调用Apex方法。

callApexImperative.js

import { LightningElement, api, wire } from 'lwc';
import getRelatedContacts from '@salesforce/apex/AccountController.getRelatedContacts';
export default class CallApexImperative extends LightningElement {
    @api recordId;
    handleButtonClick() {
        getRelatedContacts({ //imperative Apex call
            accountId: '$recordId'
        })
            .then(contacts => {
                //code to execute if related contacts are returned successfully
            })
            .catch(error => {
                //code to execute if related contacts are not returned successfully
            });
    }
}

代码重点:

  • 第2行:我们getRelatedContactsAccountController类中导入函数 。
  • 第4行:我们定义了一个公共recordId属性,以便FlexiPage可以传递该组件正在为其显示相关联系人的帐户的ID。
  • 第6-7行:当handleButtonClick框架调用该getRelatedContacts方法时,我们必须强制调用Apex方法,并传递accountId方法需要获取正确客户的相关联系人的。
  • 第9-14行:第6行中的命令式Apex调用返回了一个promise。如果Apex方法调用成功,则实现诺言并then运行该 方法。否则,承诺将被拒绝,该 catch方法将运行。

在Lightning Web组件中使用记录列表的首选方法是使用 基本组件。使用创建表格数据的功能,如无限滚动,内联编辑,标题和行级的动作,调整大小,等等。该UI组件需要提供数据。生成该数据的最常见方法是以本模块前面介绍的任何一种方式调用Apex。 lightning-datatablelightning-datatable

部署在表中列出记录的Lightning Web组件

让我们来看一个示例,该示例在中显示现有帐户的列表 lightning-datatable。我们将使用Apex并@wire检索记录。

  1. 创建一个名为的Apex类AccountController
    1. 在“资源管理器”窗格中,右键单击classes文件夹,然后选择SFDX:Create Apex Class
    2. 输入班级名称,AccountController然后按 Enter
    3. 再次 按Enter接受默认目录。
  2. 用以下代码替换AccountController类的内容:
    public with sharing class AccountController {
        @AuraEnabled(cacheable=true)
        public static List<Account> getAccounts() {
            return [
                SELECT Name, AnnualRevenue, Industry
                FROM Account
                WITH SECURITY_ENFORCED
                ORDER BY Name
            ];
        }
    }

    代码重点:

    • 第2行:我们使用注释方法, @AuraEnabled(cacheable=true)以便将结果缓存。
    • 第3行:我们getAccounts在Apex中定义了方法,以执行读取操作并检索现有帐户。
  3. 创建名为的Lightning Web组件accountList
  4. 用以下代码替换accountList.js文件的内容:
    import { LightningElement, wire } from 'lwc';
    import NAME_FIELD from '@salesforce/schema/Account.Name';
    import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
    import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
    import getAccounts from '@salesforce/apex/AccountController.getAccounts';
    const COLUMNS = [
        { label: 'Account Name', fieldName: NAME_FIELD.fieldApiName, type: 'text' },
        { label: 'Annual Revenue', fieldName: REVENUE_FIELD.fieldApiName, type: 'currency' },
        { label: 'Industry', fieldName: INDUSTRY_FIELD.fieldApiName, type: 'text' }
    ];
    export default class AccountList extends LightningElement {
        columns = COLUMNS;
        @wire(getAccounts)
        accounts;
    }

    代码重点:

    • 第2至4行:与前面的示例一样,我们导入字段引用。
    • 第5行:我们getAccounts从AccountController类导入函数。
    • 第13行:我们@wire与 getAccounts函数一起使用来检索数据。
    • 第14行:我们将结果存储在accounts属性中。如果操作成功,则可以在上访问记录 accounts.data。如果失败,则错误出现在中 accounts.error
  5. 用以下代码替换accountList.html文件的内容:
    <template>
        <lightning-card>
            <template if:true={accounts.data}>
                <lightning-datatable
                    key-field="Id"
                    data={accounts.data}
                    columns={columns}
                >
               </lightning-datatable>
            </template>
        </lightning-card>
    </template>

    代码重点:

    • 行4-9:我们定义的lightning-datatable基础组件使用accounts.datacolumns被JavaScript文件中填充。
  6. 保存您的AccountController类。
  7. 使用以下代码替换accountList.js-meta.xml的内容,以便该组件可在应用程序页面上使用:
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>48.0</apiVersion>
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__AppPage</target>
        </targets>
    </LightningComponentBundle>
  8. 保存所有三个组件文件。
  9. force-app / main / default文件夹部署到您的Trailhead Playground。
  10. 在您的Trailhead游乐场中,导航到Lightning App Builder,然后打开“使用数据”页面。
  11. accountList组件拖到页面的主要区域。
  12. 保存页面。
  13. 返回“使用数据”页面以查看新组件。

注意

使用闪电数据表组件时需要考虑的一些事项。

  • 如今,闪电数据表组件不支持某些数据类型。但是,您可以使用自定义类型。要了解更多信息,请滚动至文档中的创建自定义数据类型 。
  • 闪电数据表组件目前无法在移动设备上使用。如果您需要支持移动设备,请创建一个自定义表。

现在,您知道了与Lightning Web组件中的Salesforce数据进行交互的几种方法。接下来,您将学习如何在发生服务器错误时进行处理。

闪电Web组件和Salesforce数据 – 使用闪电数据服务来处理数据

学习目标 

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

  • 构建包含lightning-record-*-form基础组件的解决方案。
  • 使用闪电数据服务(LDS)线适配器读取数据。
  • 使用LDS功能修改数据。

如果这是您首次尝试Lightning Web Components,请等待。退后一步。在完成本模块之前,请确保您完成了 Lighthead Web Components基础知识 模块,并且 在Trailhead上了解了如何使用JavaScript。您在此处所做的工作基于此处的概念和工作。

在Lightning Web Components中使用数据

在Lightning Web组件中,有几种使用Salesforce数据的方法。知道针对特定用例使用哪种解决方案,可使您编写更少的代码,更简单的代码以及更易于维护的代码。针对每种情况使用最佳解决方案还可以提高组件和应用程序的性能。

在本模块中,您将学习何时以及如何使用不同的解决方案。我们将首先审查最简单但可定制性最少的选项。稍后,我们考虑更复杂和更可定制的选项。

使用Lightning数据服务处理数据

Lightning Data Service是使用Salesforce数据的首选(也是最简单)方式。借助Lightning Data Service,开发人员可以使用JavaScript将组件连接到Salesforce数据。

Lightning Data Service还通过对安全的用户界面API端点进行服务器调用来提供安全性。通过在所有组件之间使用客户端共享缓存,Lightning Data Service可以最大化性能。缓存记录时,将从缓存中检索记录,从而消除了对服务器的不必要调用。

Lightning Data Service在整个应用程序生命周期内跨多个组件和客户端维护一致的最新数据。如果多个组件使用Lightning Data Service处理记录,并且其中一个更新记录,则其他组件将自动反映该更新。

在以下各节中,我们重点介绍了使用Lightning Data Service处理Salesforce数据的不同方法。

使用记录表单基础组件读取或修改数据

在Lightning Web组件中使用单个记录的最简单方法是使用这些lightning-record-*-form组件。这些基本组件在后台使用Lightning Data Service,并继承其缓存和同步功能。每个基本组件都为您提供了不同的功能和自定义级别。

  • lightning-record-form基本组件是最简单的组件。使用lightning-record-form,您可以指定布局,并允许管理员声明性地配置表单字段。您还可以指定字段的有序列表,以编程方式定义显示的内容。lightning-record-form允许您查看和编辑记录。
  • lightning-record-view-form基本组件使您可以查看记录。
  • lightning-record-edit-form基本组件允许您编辑记录。

选择lightning-record-view-form或者lightning-record-edit-form当你需要自定义表单布局,预填充字段值,或变更记录数据的呈现方式。

这是lightning-record-form用于创建帐户的示例。

accountCreator.html

<template>
    <lightning-card>
        <lightning-record-form
            object-api-name={objectApiName}
            fields={fields}
            onsuccess={handleSuccess}>
        </lightning-record-form>
    </lightning-card>
</template>

accountCreator.js

import { LightningElement } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import REVENUE_FIELD from '@salesforce/schema/Account.AnnualRevenue';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
export default class AccountCreator extends LightningElement {
    objectApiName = ACCOUNT_OBJECT;
    fields = [NAME_FIELD, REVENUE_FIELD, INDUSTRY_FIELD];
    handleSuccess(event) {
        const toastEvent = new ShowToastEvent({
            title: "Account created",
            message: "Record ID: " + event.detail.id,
            variant: "success"
        });
        this.dispatchEvent(toastEvent);
    }
}

代码重点:

accountCreator.html 

  • 第3行:通过lightning-record-form在标记中使用,我们可以获得Lightning Data Service提供的所有安全性和性能优势。当lightning-record-form未指定时recordId,它将以edit模式运行,并在提交时创建一条记录。
  • 第4行:绑定object-api-name属性指示要加载的对象的类型。
  • 第5行:绑定fields属性指示要在表单中显示的字段。
  • 第6行:我们设置handleSuccesssuccess事件的处理程序。

accountCreator.js 

  • 第3至6行:在文件的开头,我们导入对Account对象及其字段的引用。以这种方式引用对象和字段可确保引用完整性。Salesforce会验证对象和字段是否存在,防止它们被删除,并确保它们包含在引用该组件的变更集和程序包中。导入对象和字段引用可确保如果重命名对象或字段,组件代码仍然可以正常工作。
  • 第10行:我们为handleSuccess事件定义事件处理程序successhandleSuccess保存操作成功时执行。
  • 第11至17行:我们通过firing显示一条敬酒消息ShowToastEvent,其中event.detail.idid对新创建的记录的属性的引用。

如果您需要的自定义功能超出了lightning-record-*-form组件提供的功能,则可以使用电线适配器或JavaScript函数直接调用Lightning Data Service。 

使用LDS线适配器读取数据

LDS线适配器 是使用Salesforce数据的另一种方法。使用有线适配器读取Salesforce数据(记录)和元数据(布局详细信息,对象上的字段,等等)。要使用它们,请用装饰一个属性或函数@wire 并指定电线适配器。

LDS有线适配器首先检查LDS缓存,并仅在需要时才从服务器请求数据。适配器会相应地更改和刷新数据。例如,当参数值更改或其他组件修改了Lightning Data Service缓存中的数据时,适配器会将新数据置备到有线属性或功能。

我们来看一个使用getRecord线适配器的示例 。

wireGetRecordProperty.js

import { LightningElement, api, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name';
export default class WireGetRecordProperty extends LightningElement {
    @api recordId;
    @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] })
    account;
}

代码重点:

  • 第2行:我们导入getRecord电线适配器。
  • 第3行:就像在accountCreator示例中所做的一样,我们导入对该Account.Name字段的引用。(在第6行中,我们用它告诉getRecord电线适配器要检索的字段。)
  • 第5行:将wireGetRecordProperty组件放置在记录页面上时,@api recordId让父组件( FlexiPage)将当前记录的ID传递给该组件。
  • 第6行:要关联account属性,我们应用@wire装饰器并指定要调用的关联适配器(getRecord),以及适配器所需的参数(recordIdfields)。
  • 第7行:电线适配器为account属性设置了一个值流,该值流将被多次设置。如果检索到一条记录,则将其存储在中account.data。如果记录检索失败,则错误存储在中 account.error
  • 第6-7行:第一次将值分配给recordId属性时,有线适配器从服务器获取数据,并将其存储在LDS缓存中以备将来访问。通过将recordId参数作为带有$前缀的字符串传递,我们可以进行recordId反应。每次recordId更改值时,有线适配器都会从缓存或服务器中获取新数据。如果另一个组件修改了缓存的记录,则有线适配器将记录的新值分配给account属性。

wireGetRecordProperty是装饰属性的示例。我们可以 用相同的方式装饰一个函数。当您要对返回的记录执行一些逻辑时,这很有用。这是前面的示例(wireGetRecordProperty),其经过重新设计以连接函数(wiredAccount)而不是属性。

wireGetRecordFunction.js

import { LightningElement, api, wire } from 'lwc';
import { getRecord } from 'lightning/uiRecordApi';
import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name';
export default class WireGetRecord extends LightningElement {
    @api recordId;
    data;
    error;
    @wire(getRecord, { recordId: '$recordId', fields: [ACCOUNT_NAME_FIELD] })
    wiredAccount({data, error}) {
        console.log('Execute logic each time a new value is provisioned');
        if (data) {
            this.data = data;
            this.error = undefined;
        } else if (error) {
            this.error = error;
            this.data = undefined;
        }
    }
}

代码重点:

  • 第8-9行:我们不是装饰属性,而是装饰wiredAccount函数。该函数接收具有两个属性的对象作为参数:dataerror。我们使用对象 ES6解构 来解压缩对象属性。
  • 第11-17行:由于LDS线适配器不是提供单个值而是提供值流,因此wiredAccount可以多次调用该函数。结果,有线功能必须重置其影响的状态。因此,在这里,在第11至17行中,如果有线适配器提供了新数据,我们会将数据存储在data属性中,并将error属性设置为undefined。另外,如果有错误,我们会将错误存储在error属性中,并将data属性设置为undefined。

使用LDS功能修改数据

LDS线适配器非常适合读取数据,但是要创建,更新或删除记录,您需要LDS功能。请注意,尽管Lightning Web Components引擎调用了有线适配器,但是您必须强制调用函数。当创建,更新或删除记录时,LDS功能会通知LDS缓存。考虑以下示例,该示例使用createRecord LDS函数创建帐户记录。

ldsCreateRecord.js

import { LightningElement} from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import ACCOUNT_NAME_FIELD from '@salesforce/schema/Account.Name';
export default class LdsCreateRecord extends LightningElement {
    handleButtonClick() {
        const recordInput = {
            apiName: ACCOUNT_OBJECT.objectApiName,
            fields: {
                [ACCOUNT_NAME_FIELD.fieldApiName] : 'ACME'
            }
        };
        createRecord(recordInput)
            .then(account => {
                // code to execute if create operation is successful
            })
            .catch(error => {
                // code to execute if create operation is not successful
            });
    }
}

代码重点:

  • 第2行:导入createRecordLDS功能。
  • 第3至4行:导入Account对象和Account.Name字段(与前面的示例一样),以确保引用完整性。
  • 第6行:我们将handleButtonClick方法定义为事件处理程序。它响应用户单击lightning-button.html文件(未显示)中的a时发生的事件。当handleButtonClick被调用时,它将createRecord强制调用该函数。
  • 第10行:我们的事件处理程序为该Account.Name字段传递了一个字符串,适配器需要使用该字符串来创建一个新帐户。
  • 第13行:当我们强制性地调用LDS函数时,它将返回一个promise(简化执行异步调用的JavaScript对象)。
  • 第14至16行:在then方法中,我们定义了成功创建帐户后会发生的情况。
  • 第17-19行:在catch方法中,我们定义了如果帐户创建失败将发生的情况。

注意:  LDS功能仅允许您处理单个记录。尽管可以在同一组件中使用多个功能(例如,在同一操作中创建两种不同类型的记录),但是每个功能都在其自己的独立事务上运行。因此,没有通用的回滚逻辑。如果需要合并的DML操作进行事务处理,请考虑使用Apex。

要了解有关LDS电线适配器和功能以及如何使用它们的更多信息,请访问Lightning Web Components开发人员指南Salesforce开发人员博客

部署创建帐户的Lightning Web组件

现在,我们已经研究了使用Lightning Data Service的不同方法,下面我们来看一个示例。

在你开始之前

我们假设您已经设置了Salesforce DX开发环境,并且可以轻松地使用它来创建Lightning Web组件并将其部署到组织中。如果您还不熟悉此过程,请完成“快速入门:Lightning Web Components”项目。

创建一个新的Trailhead游乐场

对于此项目,您需要创建一个新的Trailhead Playground。滚动到该页面的底部,单击“启动”旁边的向下箭头,然后选择“创建Trailhead游乐场”。创建新的Trailhead游乐场通常需要3-4分钟。

注意: 是的,我们的意思是全新的Trailhead游乐场!如果您使用现有的组织或游乐场,则可能会遇到无法完成挑战的问题。

获取您的Trailhead Playground用户名和密码

转到您的Trailhead游乐场。(如果尚未打开,请滚动至该页面的底部,然后单击启动。)如果您在组织中看到一个标签为Get Your Login Credentials的标签,太好了!跳至步骤1。 

否则,请从应用启动器(应用启动器)中找到并打开Playground Starter, 然后按照以下步骤操作。如果您没有看到Playground Starter应用程序,请在Trailhead帮助中签出查找Trailhead Playground的用户名和密码

  1. 单击获取您的登录凭据 选项卡,并记下您的用户名。
  2. 单击重置我的密码。这会将电子邮件发送到与您的用户名关联的地址。
  3. 单击电子邮件中的链接。
  4. 输入新密码,确认,然后单击更改密码

准备好动手了吗?我们走吧。

在本练习中,您将Lightning Web组件添加到项目中,然后将其部署到Trailhead Playground。 

  1. 创建一个新项目:
    1. 打开Visual Studio代码。
    2. 打开命令面板:单击查看命令面板
    3. 在命令面板中,选择SFDX:创建项目
      如果您没有在列表中看到它,请键入SFDX: Create Project,然后按Enter
    4. 接受标准模板。
    5. 输入项目名称,workingWithDataInLWC然后按Enter
    6. 选择新项目的位置,然后单击“创建项目”
  2. 授权您的Trailhead游乐场:
    1. 在命令选项板中,选择(或输入)SFDX:授权组织
    2. 选择生产:login.salesforce.com,然后按Enter
    3. 对于别名,请输入lwc_and_salesforce_data,然后按Enter
    4. 使用您的Trailhead Playground用户名和密码登录。
    5. 登录到Trailhead Playground后,将其保持打开状态并返回到Visual Studio Code。
  3. 创建一个闪电Web组件:
    1. 在“资源管理器”窗格中,右键单击lwc文件夹,然后选择“ SFDX:创建闪电Web组件”
    2. 输入组件名称,accountCreator然后按Enter键
    3. 再次按Enter接受默认目录。
  4. 用 本单元前面的“使用记录表单基础组件读取或修改数据”部分中提供的代码替换accountCreator.html和accountCreator.js文件的内容。
  5. 要使此组件在组织中的应用程序页面上可用,请使用以下代码替换accountCreator.js-meta.xml文件的内容:
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
        <apiVersion>48.0</apiVersion>
        <isExposed>true</isExposed>
        <targets>
            <target>lightning__AppPage</target>
        </targets>
    </LightningComponentBundle>
  6. 保存三个文件:accountCreator.html,accountCreator.js和accountCreator.js-meta.xml。
  7. 将项目文件部署到您的Trailhead Playground。(右键单击accountCreator文件夹,然后选择“ SFDX:将源部署到组织”。)
  8. 如果您的Trailhead Playground尚未打开,请打开它。(在命令选项板中,选择(或输入)  SFDX:Open Default Org)。
  9. 在您的Trailhead游乐场中,单击 设定,然后选择设置
  10. 在“快速查找”框中,输入Lightning App Builder,然后选择Lightning App Builder
  11. 创建一个闪电页面:
    1. 点击新建
    2. 选择应用程序页面 ,然后单击下一步
    3. 对于标签,输入Working with Data,然后单击下一步
    4. 对于布局,选择Header和Left Sidebar
    5. 点击完成
  12. accountCreator组件拖到页面侧栏。
  13. 保存页面。
  14. 激活页面:保留默认的应用名称(使用数据),然后点击保存
  15. 当提示您将页面添加到导航菜单时,点击完成
  16. 打开新页面:在App Launcher搜索中,输入work,然后选择使用数据

而已。您具有一个Lightning Web组件,该组件用于lightning-record-form在“使用数据”页面上创建帐户记录。使用Lightning Data Service是在Lightning Web组件中使用Salesforce数据的一种方法。在下一单元中,您将学习如何使用Apex处理数据。

闪电Web组件基础 – 将样式和数据添加到Lightning Web组件

学习目标

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

  • 将CSS和Lightning Design System与组件一起使用。
  • 从Salesforce组织获取数据。
  • 将您的应用程序部署到组织并进行测试。

调整组件

我们几乎结束了对Lightning Web组件的介绍,但让我们来看看如何控制组件的外观并提取实时数据。我们可以使外观适应Lightning环境,并在组织中使用实时数据。在本单元中,我们将使某些文本看起来生动活泼,并从您的组织中的记录中动态绘制一个帐户名。

使用上一个单元中的Bike Selector App文件来完成此操作。

CSS和组件样式

用于闪电Web组件的CSS的实现遵循 W3C标准。您可以在CSS文件中创建样式表,该样式表会自动应用于相应的HTML文件。

Lightning Web Components封装了组件,使它们与全局DOM分开。我们通过称为Shadow DOM的机制来完成此操作。Shadow DOM是一种常见的实现,它允许组件的元素位于DOM的“子树”中(在参考资料部分提供的链接中了解有关Shadow DOM的更多信息)。该组件可以将其外观和行为保留在其他应用程序中或作为另一个组件的子代。

例如,让我们设置一辆自行车的价格,使其显示为绿色粗体。将以下.price条目添加 到detail.css 文件。

body{
  margin: 0;
}
.price {
  color: green;
  font-weight: bold;
}

部署文件。

提示

您可以右键单击detail文件夹以仅部署新文件,而无需等待整个项目的部署。

在组织中,您可能需要刷新页面以查看更改,以防被缓存。然后,当您选择一辆自行车时,价格为绿色和粗体。

价格样式使文本变为绿色和粗体。

应用闪电设计系统样式

Salesforce闪电设计系统(SLDS)是一个CSS框架,提供与Lightning Experience一致的外观。位于Lightning Experience或Salesforce移动应用程序中的Lightning Web组件可以使用SLDS,而无需任何导入语句或静态资源。

例如,您可以使用SLDS标题样式来提供细节组件文本,该文本看起来更像标准的Lightning文本。更新detail.html 文件以使用 slds-text-heading_small和 slds-text-heading_medium字体设置,如下所示。

<template>
    <template if:true={product}>
    <div class="container">
        <div class="slds-text-heading_small">{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 class="slds-text-heading_medium">Select a bike</div>
    </template>
</template>

部署文件。

现在,尝试在组织中使用该组件,看看有什么不同(您需要刷新页面)。

已应用SLDS标题字体处理。

看起来很棒!现在我们已经准备好外观。但是到目前为止,我们一直在使用从数据组件中提取的静态数据。让我们在页面上添加更多闪亮的东西…动态数据。

获取Salesforce数据

毕竟,这是一个Salesforce应用程序,您真正想要的是能够从Salesforce组织中提取动态数据。Lightning Web组件使用基于Lightning Data Service构建的电抗线服务。我们将通过一个示例将一个帐户名动态地拉入我们的应用程序。

Wire Service将数据带到您的应用程序

有线服务是我们平台的一部分,可提供数据流。@wire我们前面已经简要提到过的装饰器为您的应用程序实现了有线服务。要使用有线服务,请执行以下操作。

  1. 在JavaScript文件中导入电线适配器。
  2. 用装饰器装饰属性或函数@wire

这是语法。

import { adapterId } from 'adapter-module';
@wire(adapterId, adapterConfig)
propertyOrFunction;
  • adapterId (标识符)-电线适配器的标识符。
  • adapter-module (字符串)-包含电线适配器功能的模块的标识符。
  • adapterConfig (对象)-专用于电线适配器的配置对象。
  • propertyOrFunction—从有线服务接收数据流的私有财产或功能。如果属性用@wire装饰,则结果将返回到属性的data属性或error属性。如果函数使用@wire装饰,则结果将在具有data属性和error属性的对象中返回。

这是将其添加到 我们一直在致力于从组织中提取当前用户名的项目中的selector.js文件中的方法。

import { LightningElement, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import Id from '@salesforce/user/Id';
import NAME_FIELD from '@salesforce/schema/User.Name';
const fields = [NAME_FIELD];
export default class Selector extends LightningElement {
    selectedProductId;
    handleProductSelected(evt) {
        this.selectedProductId = evt.detail;
    }
    userId = Id;
    @wire(getRecord, { recordId: '$userId', fields })
    user;
    get name() {
        return getFieldValue(this.user.data, NAME_FIELD);
    }
}

您还可以通过编辑selector.html 文件以包含名称的方式来进行尝试。例如:

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

将选择器组件文件部署到组织中时(确保部署中包括选择器文件),应该看到以下名称,而不是Mary Jones。您可能需要刷新页面。

用户界面中动态加载的用户名。

结论

这仅仅是开始,您可以使用Lightning Web Components模型做很多事情。该模型包括对测试,安全性,Apex集成等的支持。继续探索,尝试新事物,继续建设。随着W3C Web组件标准的发展,我们的模型也将随之发展。

Lightning 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. 使用选择器组件创建一个区域页面。

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

闪电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. 使用选择器组件创建一个区域页面。

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

闪电Web组件基础 – 部署Lightning Web组件文件

学习目标

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

  • 配置Lightning Web组件文件以在组织中显示。
  • 将文件部署到组织。
  • 验证组织环境中的组件行为。

加强组织

现在是时候离开游乐场了,尽管您会发现它是一个非常有用的地方。在本单元中,我们使用带有Salesforce扩展的VS Code开发Lightning Web组件。我们将文件部署到组织中,并构建一个应用程序来使用您的组件。

你需要什么

如第一单元所述,您需要对Salesforce DX有一定的了解才能继续。要完成本单元,您需要:

  • 带Salesforce扩展包的Visual Studio代码
  • Salesforce CLI
  • 已启用开发中心的组织
  • 将My Domain部署到启用了Dev Hub的组织中的用户(在Trailhead中创建的Playground组织已为您部署了My Domain。如果将Developer Edition组织与您的Trailhead帐户相关联,请启用并部署My Domain。)

要满足其余这些要求,请完成“ 快速入门:闪电Web组件”项目。如果尚未配置,请启用Dev Hub并从组织中的“设置”菜单部署“我的域”。

设置要在组织中使用的Lightning Web组件文件

您将以上一个单元为例,将其命名为bikeCard组件并将其推送到您的组织。

注意

我们没有定义自己的样式,因此不需要CSS文件。

将组件推送到组织所需的文件:

bikeCard.html

<template>
    <div>
        <div>Name: {name}</div>
        <div>Description: {description}</div>
        <lightning-badge label={material}></lightning-badge>
        <lightning-badge label={category}></lightning-badge>
        <div>Price: {price}</div>
        <div><img src={pictureUrl}/></div>
    </div>
</template>

bikeCard.js

import { LightningElement } from 'lwc';
export default class BikeCard extends LightningElement {
   name = 'Electra X4';
   description = 'A sweet bike built for comfort.';
   category = 'Mountain';
   material = 'Steel';
   price = '$2,700';
   pictureUrl = 'https://s3-us-west-1.amazonaws.com/sfdc-demo/ebikes/electrax4.jpg';
 }

bikeCard.js-meta.xml

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <!-- The apiVersion may need to be increased for the current release -->
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>
</LightningComponentBundle>
  1. 通过选择SFDX创建项目:在VS Code中从命令面板创建项目。接受标准模板,并为其指定项目名称bikeCard
  2. 右键单击lwc文件夹,然后选择SFDX:Create Lightning Web Component,创建一个bikeCard组件文件夹和文件。创建bikeCard组件文件。
  3. 将内容保存在bikeCard \ force-app \ main \ default \ lwc下的文件中,以便在VS Code中看到以下内容:bikeCard组件文件结构。 Lightning Web组件遵循Web标准。HTML标准建议自定义元素名称包含连字符。但是,Salesforce平台不允许在组件文件夹或文件名中使用连字符。因此,我们在这里使用camelCase命名约定。
  4. 从上方复制bikeCard.html,bikeCard.js和bikeCard.js-meta.xml文件的内容
  5. 保存文件。

组件配置文件

我们尚未介绍的文件是扩展名为的组件配置文件.js-meta.xml。该文件提供了Salesforce的元数据,包括打算在Lightning App Builder中使用的组件的设计配置。

组成组件的文件,包括配置文件。

我们尚未涵盖配置文件,因为我们一直在操场上玩。现在,您将开始使用组织中的内容,您必须包括一个配置文件。

请注意,ebikes repo组件均具有此配置文件。这是ebikes回购中的 一个示例:

<?xml version="1.0" encoding="UTF-8" ?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
    <apiVersion>48.0</apiVersion>
    <isExposed>true</isExposed>
    <masterLabel>Product Card</masterLabel>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
        <target>lightningCommunity__Page</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightning__RecordPage">
            <objects>
                <object>Product__c</object>
            </objects>
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

必需的 apiVersion将组件绑定到Salesforce API版本。

isExposedtruefalse)使组件可从其他命名空间使用。仅将其设置为true才能使Lightning组件在以下特定情况下可用:

  • 从Aura中的托管软件包
  • 从另一个组织中的Lightning App Builder

可选 目标指定可以在Lightning App Builder中将组件添加到哪种Lightning页面类型。

使用targetConfigs可以指定特定于每种Lightning页面的行为,包括诸如哪些对象支持该组件之类的事情。

请参阅 文档以获取受支持语法的完整列表。

在组织中显示组件

您有两个选项可用于在UI中显示Lightning Web组件。

  1. 设置组件以支持各种灵活页类型(主页,记录主页等),然后使用Lightning App Builder将其添加到灵活页。这是最简单的方法,也是您在本单元中遵循的方法。
  2. 您还可以创建一个选项卡,该选项卡指向包含Lightning Web组件的Aura组件。Lightning Web Components Recipes存储库使用此方法。您可以在回购中查看所需的件。
    • 包装组件
    • 可见性设置
    • 标签
    • 默认应用程序配置文件

部署文件

现在,您需要将组件文件部署到启用了Dev Hub的组织中。

  1. 使用SFDX向您的Dev Hub组织进行身份验证在VS Code中从命令面板授权组织。出现提示时,接受Project Default,然后按Enter接受默认别名。如果提示允许访问,请单击允许
  2. 使用SFDX部署项目文件从VS Code中的命令面板将此源部署到组织

为您的组件创建一个新页面

由于我们设置了组件配置文件以允许在Lightning App Builder中使用组件,因此请使用UI创建一个应用程序并将组件添加到其中。

  1. 要打开您的组织,请使用SFDX:在VS Code中从命令面板打开默认组织
  2. 在设置中,在快速查找框中输入Lightning App Builder,然后选择Lightning App Builder
  3. 点击新建
  4. 选择应用程序页面,然后单击下一步
  5. 给它加上标签Bike Card,然后单击Next
  6. 选择一个地区,然后单击完成
  7. 在Lightning App Builder中,向下滚动左侧的Lightning组件列表,直到看到您的bikeCard组件。Lightning App Builder自定义组件菜单中的bikeCard组件选项。

现在,您可以将其拖动到页面上。保存页面,将其激活,然后BikeCard组件将显示在分配的页面上。

  1. 将您的bikeCard组件拖到页面布局的顶部,直到看到自行车出现。
  2. 点击保存
  3. 点击激活
  4. 对所有用户保持激活状态。并且,可以选择更改应用程序的名称或图标。
  5. 点击保存。系统会要求您将页面添加到导航菜单,但不需要这样做。在这种环境下,您仍然可以进入页面。
  6. 点击完成
  7. 单击右上角的“后退”退出Lightning App Builder。
  8. 在应用启动器( 应用启动器。)中,找到并选择Bike Card
  9. 打开它,然后查看您的组件在UI中的运行情况。您在Lightning Experience中的Bike Card应用程序。

你去了,一辆闪亮的新自行车。您已经将组件推送到组织中,在页面上可以看到它,并且可以在UI中对其进行验证。

在下一个单元中,您将构建一个具有事件处理功能的交互式组件,并将其部署到组织中进行测试。