创建 Lightning Web 组件

Lightning Web 组件是具有自己的 API 的可重用自定义 HTML 元素。

请查看这些部分,了解有关创建自己的 Lightning Web 组件的更多信息。

  • 定义组件
  • HTML 模板
  • CSS的
  • 组成
  • 字段、属性和特性
  • Javascript的
  • 访问 Salesforce 资源
  • 组件可访问性
  • 生命周期钩子

定义组件

呈现 UI 的 Lightning Web 组件必须包含 HTML 文件、JavaScript 文件和元数据配置文件。这些文件必须使用相同的名称,以便框架可以自动连接它们。服务组件(库)必须包含 JavaScript 文件和元数据配置文件。

另见

  • Lightning Web 组件视频库:LWC 剖析

HTML 模板

Lightning Web 组件的强大之处在于模板系统,它使用虚拟 DOM 来智能高效地渲染组件。最好的做法是让 LWC 操作 DOM,而不是编写 JavaScript 来执行此操作。

在 HTML 模板中使用根标记。您还可以使用嵌套标记来处理指令。<template><template>

使用 HTML 模板

使用标准 HTML 和一些 Lightning Web 组件特有的指令编写模板。

当组件呈现时,标记将替换为组件的名称 。<template><namespace-component-name>

<!-- myComponent.html -->
<template>
  <div class="slds-var-m-around_medium">Hello World</div>
</template>

例如,在浏览器控制台中,带有模板的组件呈现为 ,其中 是默认命名空间。myComponent.html<c-my-component>c

<c-my-component>
  <div class="slds-var-m-around_medium">Hello, World!</div>
</c-my-component>

HTML 模板还将数据呈现给 DOM。 使用简单的语法以声明方式将组件的模板绑定到组件的 JavaScript 类中的数据。

嵌套模板

模板可以包含带有指令的嵌套标记。<template>

指令是特殊的 HTML 属性,如 和 ,它赋予您在标记中操作 DOM 的更多权力。lwc:iffor:each

嵌套标记必须包含以下指令之一:、、或 。<template>for:eachiterator:iteratorNamelwc:iflwc:elselwc:elseifif:true|false

注意

嵌套标记不能与其他指令或 HTML 属性一起使用。无效的模板用法将被忽略 – 模板及其子级不会在 DOM 中呈现,并且在加载组件时会返回警告。<template>

例如,不要在嵌套标签上使用该属性,而是在 or 标签上使用该属性。class<template>class<div><span>

提示

如果您使用 VS Code,我们建议您安装 Salesforce 扩展包。此扩展会在您键入时标记格式错误或不正确的代码,这在使用模板指令时很有帮助。

有关根标记或嵌套标记支持哪些指令的详细信息,请参阅 HTML 模板指令。<template>

模板中的数据绑定

将组件模板中的属性绑定到组件的 JavaScript 类中的属性。

在模板中,用不带空格的大括号将属性括起来:.若要计算属性的值,请在 JavaScript 类 property 中使用 JavaScript getter。在模板中,属性可以是 JavaScript 标识符(例如,),也可以是从对象 () 访问属性的点表示法。LWC 不允许使用像 这样的计算表达式。{property}get(){}personperson.firstNameperson[2].name['John']

模板中使用的属性应包含基元值,但在 for:each 或迭代器指令中使用时除外。

示例:将组件模板属性绑定到 JavaScript 属性

若要在代码编辑器中继续操作,请打开 github.com/trailheadapps/lwc-recipes 存储库中的 、 和组件。您也可以将代码复制到 webcomponents.dev/create/lwc。hellohelloBindinghelloExpressions

下面是数据绑定的最简单示例。模板中的属性绑定到 JavaScript 类中的属性。greetinggreeting

<!-- hello.html -->
<template> Hello, {greeting}! </template>
// hello.js
import { LightningElement } from "lwc";

export default class Hello extends LightningElement {
  greeting = "World";
}

中的属性必须是有效的 JavaScript 标识符或成员表达式。例如,和 都有效。不要在属性周围添加空格,例如,不是有效的 HTML。{ }{data}{data.name}{ data }

此组件没有硬编码字符串,而是具有一个输入字段,该字段要求提供要问候的名称。

该字段使用该属性来侦听其值的更改。当值更改时,将执行 JavaScript 文件中的函数。请注意,要将函数绑定到模板,我们使用相同的语法,lightning-inputonchangehandleChangehandleChange{handleChange}

<!-- helloBinding.html -->
<template>
  <p>Hello, {greeting}!</p>
  <lightning-input label="Name" value={greeting} onchange={handleChange}></lightning-input>
</template>

我们在另一个主题中深入讨论事件处理,但请注意,在 JavaScript 类中传递了一个对象。该对象包含有关更改事件的信息。该组件使用该对象来获取用户在输入字段中输入的值。handleChangeeventeventevent

// helloBinding.js
import { LightningElement } from "lwc";

export default class HelloBinding extends LightningElement {
  greeting = "World";

  handleChange(event) {
    this.greeting = event.target.value;
  }
}

这些代码大部分是标准的 HTML 和 JavaScript。

注意

当组件重新呈现时,将重新计算模板中使用的表达式。

使用 getter 代替表达式

若要计算属性的值,请使用 JavaScript getter。例如,若要将名称转换为所有大写字母,请在 JavaScript 类中使用 getter 函数,而不是模板中的表达式。

getter 比表达式强大得多,因为它们是 JavaScript 函数。Getter 还支持单元测试,从而减少错误并增加乐趣。

定义一个 getter 来计算 JavaScript 类中的值。

get propertyName() { ... }

从模板访问 getter。

{
  propertyName;
}

在此示例中,用户输入其名字和姓氏。JavaScript getter 计算一个新值,模板呈现它:DEANNA LIuppercasedFullName

模板中的属性绑定到 JavaScript 类中的 getter。uppercasedFullNameget uppercasedFullName()

<!-- helloExpressions.html -->
<template>
  <div class="slds-m-around_medium">
    <lightning-input
      name="firstName"
      label="First Name"
      onchange={handleChange}
    ></lightning-input>
    <lightning-input name="lastName" label="Last Name" onchange={handleChange}></lightning-input>
    <p class="slds-m-top_medium">Uppercased Full Name: {uppercasedFullName}</p>
  </div>
</template>

该函数将 和 属性设置为用户输入的值。getter 将名称组合并大写。handleChangefirstNamelastNameuppercasedFullName()

// helloExpressions.js
import { LightningElement } from "lwc";

export default class HelloExpressions extends LightningElement {
  firstName = "";
  lastName = "";

  handleChange(event) {
    const field = event.target.name;
    if (field === "firstName") {
      this.firstName = event.target.value;
    } else if (field === "lastName") {
      this.lastName = event.target.value;
    }
  }

  get uppercasedFullName() {
    return `${this.firstName} ${this.lastName}`.toUpperCase();
  }
}

提示

所有字段都是反应式的。如果字段在模板中使用,或间接用于模板中使用的属性的 getter 中,则当属性的值更改时,组件将重新呈现。在此示例中,when 和 change 会重新呈现模板,因为它们在 getter 中使用,并且该属性在模板中使用。请参阅字段、对象和数组的反应性。firstName lastName uppercasedFullName

有条件地呈现 DOM 元素

若要有条件地呈现 HTML,请将 and 指令添加到包含条件内容的嵌套标记中。lwc:if|elseif={property}lwc:else<template>

提示

指令是特殊的 HTML 属性。Lightning Web 组件编程模型具有一些自定义指令,允许您使用标记来操作 DOM。

这些指令绑定到模板,根据数据是真实值还是虚假值来删除和插入 DOM 元素。lwc:if|elseif{property}

注意

不再建议使用旧指令和指令,因为我们打算在将来弃用和删除这些指令。我们建议您将其用条件指令替换为条件指令,以使您的代码面向未来。if:trueif:falselwc:if|elseif|else

此示例有两个属性和 。property1property2

<template>
  <template lwc:if={property1}> Statement1 </template>
  <template lwc:elseif={property2}> Statement2 </template>
  <template lwc:else> Statement3 </template>
</template>

这三个语句中只有一个呈现:

  • Statement1如果为 true,则呈现。property1
  • Statement2如果为 false,则呈现 true。property1property2
  • Statement3呈现 if 和 are false。property1property2

尽管该示例使用所有三个指令,并且是可选的。lwc:elseiflwc:else

让我们看另一个例子。此模板包含一个标记为“显示详细信息”的复选框。当用户选中或取消选中该复选框时,该函数将设置属性的值。如果属性为 ,则该指令将呈现嵌套模板,该模板显示 These are the details!handleChangeareDetailsVisibleareDetailsVisibletruelwc:if

<!-- helloConditionalRendering.html -->
<template>
  <lightning-card title="HelloConditionalRendering" icon-name="custom:custom14">
    <div class="slds-m-around_medium">
      <lightning-input
        type="checkbox"
        label="Show details"
        onchange={handleChange}
      ></lightning-input>
      <template lwc:if={areDetailsVisible}>
        <div class="slds-m-vertical_medium">These are the details!</div>
      </template>
    </div>
  </lightning-card>
</template>

请注意,JavaScript 不会操作 DOM,它只是更改属性的值。

// helloConditionalRendering.js
import { LightningElement } from "lwc";

export default class HelloConditionalRendering extends LightningElement {
  areDetailsVisible = false;

  handleChange(event) {
    this.areDetailsVisible = event.target.checked;
  }
}

注意

若要在标记中切换布尔属性的值,请将该值默认为 。请参见布尔属性。false

提示

此示例代码是 github.com/trailheadapps/lwc-recipes 存储库中的组件。helloConditionalRendering

渲染列表

若要呈现项列表,请使用 directive 或 the directive 循环访问数组。将该指令添加到包含要重复的 HTML 元素的嵌套标记中。for:eachiterator<template>

该指令具有 和 属性,可用于将特殊行为应用于数组中的第一个和最后一个项目。iteratorfirstlast

无论使用哪个指令,都必须使用指令为每个项目分配唯一的 ID。当列表更改时,框架使用 仅重新呈现已更改的项。模板中的 用于性能优化,在运行时不会反映在 DOM 中。keykeykey

提示

若要在代码编辑器中继续操作,请打开 github.com/trailheadapps/lwc-recipes 存储库中的 和组件。还可以将代码复制到组件 IDE。helloForEachhelloIterator

适合:每个

使用该指令时,use 用于访问当前项目。此示例不使用它,但要访问当前项的索引,请使用 .for:eachfor:item="currentItem"for:index="index"

若要将键分配给嵌套模板中的第一个元素,请使用该指令。key={uniqueId}

此示例循环访问一个名为 的数组,该数组在组件的 JavaScript 类中定义。contacts

<!-- helloForEach.html -->
<template>
  <lightning-card title="HelloForEach" icon-name="custom:custom14">
    <ul class="slds-m-around_medium">
      <template for:each={contacts} for:item="contact">
        <li key={contact.Id}>{contact.Name}, {contact.Title}</li>
      </template>
    </ul>
  </lightning-card>
</template>
// helloForEach.js
import { LightningElement } from "lwc";

export default class HelloForEach extends LightningElement {
  contacts = [
    {
      Id: 1,
      Name: "Amy Taylor",
      Title: "VP of Engineering",
    },
    {
      Id: 2,
      Name: "Michael Jones",
      Title: "VP of Sales",
    },
    {
      Id: 3,
      Name: "Jennifer Wu",
      Title: "CEO",
    },
  ];
}

重要

列表中的每个项目都必须具有 .当列表更改时,框架使用 来标识每个项目,以便它只能重新呈现已更改的项目。必须是字符串或数字,不能是对象。不能用作 的值。为传入数据集分配唯一键。若要将新项添加到数据集,请使用私有属性来跟踪和生成键。keykeykeyindexkey

迭 代

若要将特殊行为应用于列表中的第一项或最后一项,请使用指令 。在标记上使用指令。iteratoriterator:iteratorName={array}iteratortemplate

使用 iteratorName 访问以下属性:

  • value– 列表中项目的值。使用此属性可访问数组的属性。例如。{iteratorName}.value.{propertyName}
  • index– 列表中项目的索引。
  • first– 一个布尔值,指示此项目是否为列表中的第一项。
  • last– 一个布尔值,指示此项目是否为列表中的最后一项。

此示例代码使用与上一个示例相同的数组。若要将特殊呈现应用于列表中的第一项和最后一项,代码将 and 属性与指令一起使用。firstlastlwc:if

如果项目位于列表中的第一个,则标记将使用 CSS 类中定义的样式进行呈现。如果项目在列表中排在最后,则标记将使用 CSS 类中定义的样式进行呈现。<div>list-first<div>list-last

<template>
  <lightning-card title="HelloIterator" icon-name="custom:custom14">
    <ul class="slds-m-around_medium">
      <template iterator:it={contacts}>
        <li key={it.value.Id}>
          <div lwc:if={it.first} class="list-first"></div>
          {it.value.Name}, {it.value.Title}
          <div lwc:if={it.last} class="list-last"></div>
        </li>
      </template>
    </ul>
  </lightning-card>
</template>
.list-first {
  border-top: 1px solid black;
  padding-top: 5px;
}

.list-last {
  border-bottom: 1px solid black;
  padding-bottom: 5px;
}

lwc-recipes 存储库中的组件使用基本组件来显示选择列表值列表。wireGetPicklistValues lightning-input

渲染多个模板

您可能希望呈现具有多种外观的组件,但不希望将 HTML 混合在一个文件中。例如,组件的一个版本是纯文本,另一个版本显示图像和额外的文本。在这种情况下,您可以导入多个 HTML 模板并编写有条件地呈现这些模板的业务逻辑。此模式类似于某些 JavaScript 框架中使用的代码拆分。

注意

尽管一个组件可以呈现多个模板,但我们建议改用指令有条件地呈现嵌套模板。lwc:if|elseif|else

在组件包中创建多个 HTML 文件。将它们全部导入,并在方法中添加条件,以根据组件的状态返回正确的模板。该方法返回的值必须是模板引用,这是从 HTML 文件导入的默认导出。render()render()

在此示例中,模板引用是 和 。templateOnetemplateTwo

// miscMultipleTemplates.js

import { LightningElement } from "lwc";
import templateOne from "./templateOne.html";
import templateTwo from "./templateTwo.html";

export default class MiscMultipleTemplates extends LightningElement {
  showTemplateOne = true;

  render() {
    return this.showTemplateOne ? templateOne : templateTwo;
  }

  switchTemplate() {
    this.showTemplateOne = !this.showTemplateOne;
  }
}
<!-- templateOne.html -->
<template>
  <lightning-card title="Template One">
    <div>This is template one.</div>
    <p class="margin-vertical-small">
      <lightning-button label="Switch Templates" onclick={switchTemplate}> </lightning-button>
    </p>
  </lightning-card>
</template>
<!-- templateTwo.html -->
<template>
  <lightning-card title="Template Two">
    <div>This is template two.</div>
    <p class="margin-vertical-small">
      <lightning-button label="Switch Templates" onclick={switchTemplate}> </lightning-button>
    </p>
  </lightning-card>
</template>

若要从额外模板引用 CSS,CSS 文件名必须与额外模板的文件名匹配。例如,只能从 引用 CSS。它不能从 或 引用 CSS。templateTwo.htmltemplateTwo.cssmiscMultipleTemplates.csstemplateOne.css

MiscMultipleTemplates
   ├──miscMultipleTemplates.js
   ├──miscMultipleTemplates.js-meta.xml
   ├──templateOne.html
   ├──templateOne.css
   ├──templateTwo.html
   └──templateTwo.css

如果包含具有匹配名称的模板,则默认方法将返回该模板,除非包含上一示例中讨论的替代。miscMultipleTemplates.htmlrender()

提示

查看 lwc-recipes 存储库中的组件。miscMultipleTemplates