在组件的 JavaScript 类中声明字段。在组件的模板中引用它们以动态更新内容。
字段和属性几乎是可以互换的术语。组件作者声明类中的字段。类的实例具有属性。对于组件使用者来说,字段是属性。在 Lightning Web 组件中,只有组件作者用来修饰的字段才能作为对象属性公开提供给使用者。@api
属性和属性几乎是可以互换的术语,可能会造成混淆。一般来说,在 HTML 中我们谈论属性,在 JavaScript 中我们谈论属性。
提示
如果您已经开发过 Aura 组件,那么您就熟悉术语 attribute。在 Lightning Web 组件中,最接近 Aura 属性的是 JavaScript 属性。
反应
反应性是 Lightning Web 组件框架的核心系统。该框架观察字段和属性值的更改。当它观察到变化时,它会做出反应。它重新计算模板中使用的所有表达式,并重新呈现组件,从而显示新值。
字段和属性几乎是可以互换的术语。组件作者声明类中的字段。类的实例具有属性。对于组件使用者来说,字段是属性。在 Lightning Web 组件中,只有组件作者用来修饰的字段才能作为对象属性公开提供给使用者。@api
公共属性
若要公开公共属性,请使用 修饰字段。公共属性定义组件的 API。模板中使用的公共属性是反应式的。如果模板中使用的公共属性的值发生更改,则组件将重新呈现。@api
当组件重新渲染时,将重新计算模板中使用的表达式,并执行 renderedCallback()
生命周期钩子。
@api装饰器
提示
装饰器是一种 JavaScript 语言功能。@api
装饰器是 Lightning Web 组件独有的。一个字段只能有一个修饰器。
从 导入装饰器。此代码将字段公开为公共属性。@api
lwc
itemName
// todoItem.js
import { LightningElement, api } from "lwc";
export default class TodoItem extends LightningElement {
@api itemName = "New Item";
}
在模板中显示的值。itemName
<!-- todoItem.html -->
<template>
<div class="view">
<label>{itemName}</label>
</div>
</template>
此 JavaScript 类和 HTML 模板定义组件,其中是命名空间。使用该组件的组件可以设置该属性。c-todo-item
c
c-todo-item
itemName
注意
JavaScript 中的属性名称采用驼峰大小写,而 HTML 属性名称采用烤肉串大小写(破折号分隔)以匹配 HTML 标准。在 中,标记中的属性映射到 的 JavaScript 属性。todoApp.html
item-name
itemName
c-todo-item
<!-- todoApp.html -->
<template>
<div class="listing">
<c-todo-item item-name="Milk"></c-todo-item>
<c-todo-item item-name="Bread"></c-todo-item>
</div>
</template>
在其标记中使用组件的所有者组件可以通过 DOM 属性访问组件的公共属性。DOM 属性是在类中声明的公共字段。它们可以通过带有点表示法的 DOM 元素访问。在此示例中,该组件将一个公共字段声明为 ,其值可通过 (DOM 元素)实例上的 DOM 属性访问。c-todo-item
@api itemName
c-todo-item
// todoApp.js
myItem = this.template.querySelector("c-todo-item").itemName;
提示
请参阅存储库中的 CompositionBasics 示例。lwc-recipes
字段、对象和数组的反应性
如果字段的值发生更改,并且该字段在模板中使用或在模板中使用的属性的 getter 中使用,则组件将重新呈现并显示新值。如果为字段分配了对象或数组,则框架会观察到对象或数组内部的一些更改,例如在分配新值时。
当组件重新渲染时,将重新计算模板中使用的表达式,并执行 renderedCallback()
生命周期钩子。
当您在“名字”或“姓氏”字段中输入值时,组件会将其转换为大写并显示。

<!-- helloExpressions.html -->
<template>
<lightning-card title="HelloExpressions" icon-name="custom:custom14">
<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>
</lightning-card>
</template>
组件的类定义了 和 字段。由于它们在模板 () 中使用的属性的 getter 中使用,因此当其值更改时,组件会重新呈现。firstName
lastName
uppercasedFullName
// helloExpressions.js
import { LightningElement } from "lwc";
export default class TrackExample 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}`.trim().toUpperCase();
}
}
注意
字段是反应式的。Expando 属性是在运行时添加到对象的属性,不是响应式的。
提示
请参阅存储库中的 helloExpressions 组件。lwc-recipes
反应性注意事项
尽管字段是反应式的,但 LWC 引擎以浅层方式跟踪字段值更改。通过使用 比较值标识来将新值分配给字段时,将检测到更改。此方法适用于数字或布尔值等基元类型。===
import { LightningElement } from "lwc";
export default class ReactivityExample extends LightningElement {
bool = true;
number = 42;
obj = { name: "John" };
checkMutation() {
this.bool = false; // Mutation detected
this.number = 42; // No mutation detected: previous value is equal to the newly assigned value
this.number = 43; // Mutation detected
this.obj.name = "Bob"; // No mutation detect: `obj` field value is not reassigned
this.obj = { name: "John" }; // Mutation detected - redefining the object with the same value creates a new object
this.obj = { ...this.obj, title: "CEO" }; // Mutation detected
}
}
在操作复杂类型(如对象和数组)时,必须创建一个新对象并将其分配给要检测更改的字段。
为了避免在处理复杂对象时出现此类问题,请使用修饰器深入跟踪对字段值所做的更改。@track
跟踪对象和数组内部的更改
若要观察对象属性或数组元素的更改,请使用 修饰字段。@track
当字段修饰有 时,Lightning Web 组件会跟踪对以下各项内部值的更改:@track
- 使用以下方式创建的普通对象
{}
- 使用
[]
该框架以递归方式观察对普通对象和数组的突变,包括嵌套对象、嵌套数组以及对象和数组的混合。还处理循环引用。
但是,该框架不会观察到对复杂对象(例如继承自 、类实例、 、 或 的对象)的突变。Object
Date
Set
Map
@track装饰器
观察对象的属性
要告诉框架观察对象属性的变化,请使用 修饰字段。@track
注意
如前所述,在不使用 的情况下,框架会观察到为字段分配新值的更改。如果新值不是以前的值,则组件将重新呈现。@track
===
例如,让我们稍微更改代码以声明字段,该字段包含一个具有两个属性的对象,以及 .该框架会观察到将新值分配给 的更改。fullName
firstName
lastName
fullName
fullName = { firstName: "", lastName: "" };
此代码为字段分配一个新值,以便组件重新呈现。fullName
// Component rerenders.
this.fullName = { firstName: "John", lastName: "Doe" };
但是,如果我们为对象的某个属性分配一个新值,则组件不会重新呈现,因为不会观察到这些属性。
// Component doesn't rerender.
this.fullName.firstName = "John";
该框架会观察到为字段分配新值的更改。此代码不会执行此操作,而是为对象的属性分配一个新值。fullName
firstName
fullName
要告诉框架观察对象属性的变化,请使用 修饰字段。现在,如果我们更改任一属性,组件就会重新渲染。fullName
@track
// Component rerenders.
@track fullName = { firstName : '', lastName : ''};
this.fullName.firstName = 'John';
如果属性包含对象,若要跟踪对象属性的更改,请使用 注释该属性。为了理解,让我们修改我们的示例。我们的示例初始化 and 为空字符串,这些字符串是原始值,因此组件在它们更改时会重新呈现。@track
firstName
lastName
使用新属性重新呈现对象
仅当更新了在上一个渲染周期中访问的属性时,组件才会重新渲染,即使对象使用 批注了 。这样可以防止组件过度重新渲染,@track
考虑这个跟踪对象和一个打印对象属性的 getter。
@track obj = {value1: 'Hello'};
get words() {
return Object.entries(this.obj)
.map(([key, value]) => ({key, value}));
}
在第一个渲染周期中,框架会记录所访问的内容。任何不影响的突变都会被忽略,因为它不会影响呈现的内容。因此,更改 会触发重新呈现,但向 添加新属性或更改不会触发重新呈现。obj.value1
obj
value1
value1
obj
value2
// Component rerenders.
setValue1(e) {
this.obj.value1 = 'Hello World';
}
// Component doesn’t rerender.
setValue2(e) {
this.obj.value2 = 'Hello LWC';
}
若要在添加新属性时重新呈现组件,请将该对象分配给具有这两个值的新对象。
setValue2(e) {
this.obj = {
...this.obj,
value2: 'Hello LWC'
};
}
观察数组的元素
另一个用例是告诉框架观察数组元素的变化。@track
如果不使用 ,框架会观察到为字段分配新值的更改。@track
arr = ["a", "b"];
当您将新值分配给 时,组件将重新呈现。arr
// Component rerenders.
this.arr = ["x", "y", "z"];
但是,如果我们在数组中更新或添加元素,则该组件不会重新渲染。
// Component doesn’t rerender.
this.arr[0] = "x";
this.arr.push("c");
若要告诉框架观察数组元素的变化,请使用 此外,框架不会自动将数组转换为字符串以更新数组元素。要返回更新的字符串,请使用 getter 将数组的元素转换为字符串。arr
@track
join()
@track arr = ['a','b'];
get computedArray() { return this.arr.join(','); }
update() {
this.arr[0] = 'x';
this.arr.push('c');
}
观察复杂物体
让我们看一个字段为 的组件,其类型为 。该模板有几个按钮,用于更改 的内部状态。此示例突出显示了创建对象,因为它不是普通的 JavaScript 对象,LWC 引擎不会观察到内部状态突变,即使代码使用 .x
Date
x
new Date()
@track
// trackDate.js
import { LightningElement, track } from "lwc";
export default class TrackDate extends LightningElement {
@track x = new Date();
initDate() {
this.x = new Date();
}
updateDate() {
this.x.setHours(7); // No mutation detected
}
}
与前面的示例类似,该模板有几个按钮可以更改 的内部状态。x
<!-- trackDate.html -->
<template>
<p>Date: {x}</p>
<button onclick={initDate}>Init</button>
<button onclick={updateDate}>Update</button>
</template>
单击“初始化”按钮时,将观察到更改并重新呈现模板。Lightning Web Components 观察到它指向一个新对象。但是,单击“更新”时,不会重新呈现模板。Lightning Web 组件不会观察到对象值的变化。x
Date
Date
若要确保在值更改时重新呈现模板,请克隆现有日期并更新其值。
updateDate() {
const cloned = new Date(this.x.getTime());
cloned.setHours(7);
// Assign the new date instance to rerender the component.
this.x = cloned;
}
注意
将属性设置为无法跟踪的值时,将记录警告。如果尝试调试组件在更改时未重新呈现的方案,请查看浏览器控制台。在我们的示例中,浏览器控制台会记录以下有用的警告:
Property "x" of [object:vm TrackDate] is set to a non-trackable object, which means changes into that object cannot be observed.
属性和属性名称
JavaScript 中的属性名称采用驼峰大小写,而 HTML 属性名称采用烤肉串大小写(破折号分隔)以匹配 HTML 标准。
例如,名为 的 JavaScript 属性映射到名为 的 HTML 属性。itemName
item-name
// child.js
import { LightningElement, api } from "lwc";
export default class extends LightningElement {
@api itemName;
}
<!-- parent.html -->
<template>
<c-child item-name="Child item"></c-child>
</template>
JavaScript 属性名称
不要以这些字符开头属性名称。
on
(例如,onClick
)aria
(例如,ariaDescribedby
)data
(例如,dataProperty
)
不要将这些保留字用于属性名称。
slot
part
is
HTML 属性名称
模板中的 HTML 属性不能包含大写字符。属性名称可以以以下字母开头:
- 小写字母字符
- 下划线 (
_
) - 美元符号 (
$
) - 可选连字符后跟字母字符(
-a
)
属性名称可以包含重复的下划线 () 或下划线后跟连字符 ()。__
_-
如果连字符不是属性名称中的第一个字符,则允许使用连字符后跟下划线 ()。例如,这些是有效的属性名称:-_
_myattribute
$myattribute
my_-attribute
如果 JavaScript 属性以大写字符开头,并且希望通过 HTML 属性进行设置,则必须使用特殊语法。属性名称的大写字符为小写,并以连字符 为前缀。前导连字符告诉引擎,属性名称中的第一个字母字符在 JavaScript 类中是用前导大写字符声明的。例如,JavaScript 属性对应于 HTML 属性。-upper
@api Upper
upper
在 JavaScript 中访问 HTML 全局属性
不建议使用 HTML 全局属性,这些属性类似于所有 HTML 元素,并且是所有 HTML 元素通用的属性。如果确实使用全局 HTML 属性,请使用 .classtitle@api
某些 HTML 全局属性不遵循 Lightning Web 组件驼峰大小写和烤肉串大小写约定。如果在 JavaScript 中为这些 HTML 全局属性之一创建 getter 或 setter,请使用此列表中的大小写。
HTML 全局属性 | JavaScript 中的属性 |
---|---|
accesskey | accessKey |
bgcolor | bgColor |
colspan | colSpan |
contenteditable | contentEditable |
crossorigin | crossOrigin |
datetime | dateTime |
for | htmlFor |
formaction | formAction |
ismap | isMap |
maxlength | maxLength |
minlength | minLength |
novalidate | noValidate |
readonly | readOnly |
rowspan | rowSpan |
tabindex | tabIndex |
usemap | useMap |
例如,要访问 JavaScript 中的 HTML 属性,请使用 .maxlength
textarea
maxLength
此外,要从 JavaScript 访问 HTML 属性,请使用 .for
htmlFor
在 JavaScript 中访问 ARIA 属性
ARIA 属性支持辅助技术。要在 JavaScript 中访问这些属性,请使用驼峰大小写。例如,要访问 ,请使用 .要访问 ,请使用 .aria-checked
ariaChecked
aria-errormessage
ariaErrorMessage
Web API 属性
Lightning Web 组件反映了许多 Web API 的属性。
元素
Lightning Web 组件反映了 Element
界面的这些属性。
children
, classList
, className
, firstElementChild
, getAttribute
, getAttributeNS
, getBoundingClientRect
, getElementsByClassName
, getElementsByTagName
, hasAttribute
, id
, lastElementChild
, querySelector
, querySelectorAll
, removeAttribute
, removeAttributeNS
, setAttributeNS
, setAttribute
, shadowRoot
, slot
请参阅 Shadow DOM、访问组件拥有的元素以及将标记传递到插槽中。
在 Salesforce 组织中启用 Lightning Web Security 后,setAttributeNS、setAttribute 和 shadowRoot 会因失真而修改。
事件目标
Lightning Web 组件反映了 EventTarget
接口的这些属性。
addEventListener
, dispatchEvent
, removeEventListener
请参阅与事件通信。
HTMLElement
Lightning Web 组件反映了 HTMLElement
接口的这些属性。
accessKeyLabel
, contentEditable
, dataset
, dir
, hidden
, isContentEditable
, lang
, offsetHeight
, offsetLeft
, offsetParent
, offsetTop
, offsetWidth
, title
在 Salesforce 组织中启用 Lightning Web Security 时,数据集会因失真而修改。
节点
Lightning Web 组件反映了 Node
界面的这些属性。
childNodes
, firstChild
, isConnected
, lastChild
请参见在 DOM 中插入或删除组件时运行代码。
WAI-ARIA 状态和属性
Lightning Web 组件反映了这些 WAI-ARIA 状态和属性。
ariaActiveDescendant
, ariaAtomic
, ariaAutoComplete
, ariaBusy
, ariaChecked
, ariaColCount
, ariaColIndex
, ariaColSpan
, ariaControls
, ariaCurrent
, ariaDescribedBy
, ariaDetails
, ariaDisabled
, ariaErrorMessage
, ariaExpanded
, ariaFlowTo
, ariaHasPopup
, ariaHidden
, ariaInvalid
, ariaKeyShortcuts
, ariaLabel
, ariaLabelledBy
, ariaLevel
, ariaLive
, ariaModal
, ariaMultiLine
, ariaMultiSelectable
, ariaOrientation
, ariaOwns
, ariaPlaceholder
, ariaPosInSet
, ariaPressed
, ariaReadOnly
, ariaRelevant
, ariaRequired
, ariaRoleDescription
, ariaRowCount
, ariaRowIndex
, ariaRowSpan
, ariaSelected
, ariaSetSize
, ariaSort
, ariaValueMax
, ariaValueMin
, ariaValueNow
, ariaValueText
请参阅组件可访问性。
使用 getter 和 setter 修改数据
若要在每次设置公共属性时执行逻辑,请编写自定义 setter。
如果为公共属性编写 setter,则还必须编写 getter。用 注释 getter 或 setter,但不能同时注释两者。最佳做法是注释 getter。@api
若要将属性值保存在 getter 和 setter 中,请使用字段。此示例使用该属性,该属性以下划线为前缀,以指示该属性是私有的。_uppercaseItemName
此示例组件将字符串转换为大写。<c-todo-item>
<!-- todoItem.html -->
<template> {itemName} </template>
属性值通过 getter 提供给模板。
// todoItem.js
import { LightningElement, api } from "lwc";
export default class TodoItem extends LightningElement {
_uppercaseItemName;
@api
get itemName() {
return this._uppercaseItemName;
}
set itemName(value) {
this._uppercaseItemName = value.toUpperCase();
}
}
提示
有关使用 getter 和 setter 的另一个示例,请参阅 lwc-recipes 示例存储库中的 和 组件。apiSetterGettertodoList
Boolean 属性
标准 HTML 元素上的布尔属性是通过将属性添加到元素来设置的。如果缺少该属性,则该属性默认为 。因此,属性的默认值始终为 。Lightning Web 组件对布尔属性使用相同的原则。true
false
false
静态设置属性
始终将布尔公共属性的默认值设置为 。如果将默认值设置为 instead in ,则无法静态地将值切换为 in markup。false
true
bool.js
false
// bool.js
import { LightningElement, api } from "lwc";
export default class Bool extends LightningElement {
@api show = false;
}
下面是 HTML 文件。
<!-- bool.html -->
<template>
<p>show value: {show}</p>
</template>
父组件包括 ,它显示默认值 ,因为该属性未添加到 。c-bool
false
show
<c-bool>
重要
在标记中指定的唯一方法是省略 boolean 属性。在标记中设置的计算结果为 。false
show="false"
true
<!-- parent.html -->
<template>
<c-bool></c-bool>
</template>
若要将属性设置为 ,请将具有空值的属性添加到标记中。此版本的 显示属性的值。show
true
show
c-parent
true
show
<!-- parent.html -->
<template>
<c-bool show></c-bool>
</template>
的值是,但属性不会反映在呈现的 HTML 中,除非您通过调用 来显式反映该属性。请参阅将 JavaScript 属性反映为 HTML 属性。showtrueshowsetAttribute
注意
当布尔属性的值为 时,呈现的 HTML 为 。true
<my-component my-attribute>
动态设置属性
若要动态切换值,请从父组件传递动态计算值。例如:
<!-- parent.html -->
<template>
<c-bool show={computedValue}></c-bool>
</template>
使用 JavaScript getter in 返回 的值。parent.js
{computedValue}
将 JavaScript 属性反映为 HTML 属性
您可以控制公共 JavaScript 属性是否在 Lightning Web 组件的渲染 HTML 中显示为属性。在创建可访问的组件时,允许属性显示为属性尤为重要,因为屏幕阅读器和其他辅助技术使用 HTML 属性。
默认情况下,所有 HTML 属性都是响应式的。当组件 HTML 中的属性值发生更改时,将重新呈现该组件。
当您通过将某个属性公开为公共属性来控制该属性时,默认情况下,该属性将不再显示在 HTML 输出中。若要将值作为属性传递到呈现的 HTML(以反映属性),请为属性定义 getter 和 setter 并调用该方法。setAttribute()
您还可以在 setter 中执行操作。使用字段保存计算值。
此示例公开为公共属性。它将标题转换为大写,并使用该属性来保存标题的计算值。setter 调用以将属性的值反映到 HTML 属性。title
_privateTitle
setAttribute()
// myComponent.js
import { LightningElement, api } from "lwc";
export default class MyComponent extends LightningElement {
_privateTitle;
@api
get title() {
return this._privateTitle;
}
set title(value) {
this._privateTitle = value.toUpperCase();
this.setAttribute("title", this._privateTitle);
}
}
/* parent.html */
<template>
<c-my-component title="Hover Over the Component to See Me"></c-my-component>
</template>
/* Generated HTML */
<c-my-component title="HOVER OVER THE COMPONENT TO SEE ME">
<div>Reflecting Attributes Example</div>
</c-my-component>
要确保您了解 JavaScript 属性如何反映到 HTML 属性,请查看不调用 .生成的 HTML 不包含该属性。setAttribute()
title
// myComponent.js
import { LightningElement, api } from "lwc";
export default class MyComponent extends LightningElement {
_privateTitle;
@api
get title() {
return this._privateTitle;
}
set title(value) {
this._privateTitle = value.toUpperCase();
// this.setAttribute('title', this._privateTitle);
}
}
/* parent.html */
<template>
<c-my-component title="Hover Over the Component to See Me"></c-my-component>
</template>
/* Generated HTML */
<c-my-component>
<div>Reflecting Attributes Example</div>
</c-my-component>
在设置值之前,请检查使用者是否已经设置了该值。
// myComponent.js
import { LightningElement } from "lwc";
export default class MyComponent extends LightningElement {
connectedCallback() {
const tabindex = this.getAttribute("tabindex");
// Set the tabindex to 0 if it hasn’t been set by the consumer.
if (!tabindex) {
this.setAttribute("tabindex", "0");
}
}
}
在此标记中设置 using 结果。tabindex
this.setAttribute()
<c-my-component tabindex="0"></c-my-component>
要设置这些属性,请使用 .setAttribute()
for
aria-activedescendant
aria-controls
aria-describedby
aria-details
aria-errormessage
aria-flowto
aria-labelledby
aria-owns
要从呈现的 HTML 中隐藏 HTML 属性,请调用 .removeAttribute()
管理 Getter 中的属性依赖关系
HTML 中的属性变成了 JavaScript 中的属性赋值。在这两种情况下,都不能保证分配顺序。要检查是否存在其他属性,请使用 getter。
在模板中使用 getter 引用。不要使用 getter,也不要使用依赖于其他属性中的值的 setter。@api
@api
@api
假设我们有一个数据表组件,该组件在所选行上显示复选标记。我们有两个独立的属性和 ,它们依赖于另一个属性。rows
selectedRows
<template>
<c-datatable selected-rows="1,2" rows="1,2,3,4"> </c-datatable>
</template>
由于无法保证接收属性的顺序,因此请使用 getter 来检查依赖关系。
export default class Datatable extends LightningElement {
@track state = {};
@api
get rows() {
return this.state.rows;
}
set rows(value) {
this.state.rows = value;
// Check to see if the rows have
// been marked as selected.
if (this.state.selectedRows && !this.selectedRowsSet) {
this.markSelectedRows();
this.selectedRowsSet = true;
}
}
@api
set selectedRows(value) {
this.state.selectedRows = value;
// If rows haven’t been set,
// then we can't mark anything
// as selected.
if (!this.state.rows) {
this.selectedRowsSet = false;
return;
}
this.markSelectedRows();
}
get selectedRows() {
return this.state.selectedRows;
}
markSelectedRows() {
// Mark selected rows.
}
}
使用 getter 和 setter 可确保公共 API 协定易于执行。组件不应更改用 批注的属性的值。@api
如果某些内容在设定的时间依赖于该值,则规范化 setter 中的数据,例如,以编程方式将 CSS 类附加到元素上。返回 getter 中的原始值。规范化也可以在 getter 中完成,这样即使使用者没有设置任何内容,模板也可以访问值。
@track state = {
selected : false
};
privateSelected = 'false';
@api
get selected() {
return this.privateSelected;
}
set selected(value) {
this.privateSelected = value;
this.state.selected = normalizeBoolean(value)
}