当使用 map() 指令或在模板中直接提供可迭代对象时,Lit 会创建一个 DOM 节点列表并按迭代顺序更新它们,高效地复用之前渲染的节点。这种技术应该仅在 Lit 控制所有渲染状态时使用(通常都是这种情况)。

然而,当依赖 DOM 节点来维护不由 Lit 控制的状态时,可能会出现意外行为,下面的示例将演示这一点。在这种情况下,应改用 repeat() 指令。

示例

Permalink to "示例"

看看这个示例,其中每个任务项都使用 map() 指令渲染为带有复选框的 <li>。有按字母升序或降序排列列表项的按钮。标签文本由模板表达式提供,但没有明确的组件状态来保存该项是否被选中。

选中其中一项并更改排序顺序。注意,项的标签文本改变了,但复选框的选中位置没有改变。这是因为不由 Lit 控制的复选框状态保留在 DOM 节点上。在更新期间,Lit 只更新持有标签的文本节点的值,而不会重新排列 DOM 节点。

使用 repeat() 指令可以将列表项和复选框与数组中的特定项绑定在一起。使用带有键函数的此指令可以让 Lit 在更新之间维护键到 DOM 的关联关系,在需要时移动 DOM 节点。

首先导入 repeat() 指令。

// my-element.ts
import {repeat} from 'lit/directives/repeat.js';
// my-element.js
import {repeat} from 'lit/directives/repeat.js';

repeat() 替代 map() 指令,提供可迭代对象、一个为特定项返回唯一标识符的键函数,以及为每项渲染的模板。

// my-element.ts
render() {
return html`
<ul>
${repeat(
this.tasks,
(task) => task.id,
(task) => html`
<li>
<label><input type="checkbox" />${task.label} (${task.id})</label>
</li>
`
)}
</ul>
`;
}
// my-element.js
render() {
return html`
<ul>
${repeat(
this.tasks,
(task) => task.id,
(task) => html`
<li>
<label><input type="checkbox" />${task.label} (${task.id})</label>
</li>
`
)}
</ul>
`;
}

通过选中一项并更改排序顺序来确认其是否正常工作。选中标记现在应该会随原始标签一起移动。

提供的键函数必须为每一项返回唯一的键。

如果省略键函数——或者提供的键函数只返回索引——repeat() 的行为与 map() 完全相同。更多信息请参阅 repeat 文档。另请参阅何时使用 map 或 repeat以获取选择使用哪种方式的指导。