当使用 map() 指令或在模板中直接提供可迭代对象时,Lit 会创建一个 DOM 节点列表并按迭代顺序更新它们,高效地复用之前渲染的节点。这种技术应该仅在 Lit 控制所有渲染状态时使用(通常都是这种情况)。
然而,当依赖 DOM 节点来维护不由 Lit 控制的状态时,可能会出现意外行为,下面的示例将演示这一点。在这种情况下,应改用 repeat() 指令。
看看这个示例,其中每个任务项都使用 map() 指令渲染为带有复选框的 <li>。有按字母升序或降序排列列表项的按钮。标签文本由模板表达式提供,但没有明确的组件状态来保存该项是否被选中。
选中其中一项并更改排序顺序。注意,项的标签文本改变了,但复选框的选中位置没有改变。这是因为不由 Lit 控制的复选框状态保留在 DOM 节点上。在更新期间,Lit 只更新持有标签的文本节点的值,而不会重新排列 DOM 节点。
使用 repeat() 指令可以将列表项和复选框与数组中的特定项绑定在一起。使用带有键函数的此指令可以让 Lit 在更新之间维护键到 DOM 的关联关系,在需要时移动 DOM 节点。
首先导入 repeat() 指令。
// my-element.tsimport {repeat} from 'lit/directives/repeat.js'; // my-element.jsimport {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以获取选择使用哪种方式的指导。