重复实用程序
repeat 实用程序是 Markup 推荐的呈现可迭代数据或重复内容的方法。它处理模板的缓存和跟踪等事务,确保列表更改仅发生在需要它们的项目上。
javascript
html`${repeat(todos, renderTodo)}`为什么要使用重复?
Markup 模板已经处理数组,但与任何其他注入值一样,Markup 跟踪整个事物,而不是其单个项目。
javascript
const [todos, updateTodos] = state([])
html`${() => todos().map(renderTodo)}`.render(document.body)
updateTodos((prev) => [
...prev,
{
name: 'Go to gym',
status: 'pending',
},
])就渲染列表而言,上面的代码可以正常工作。当单个项目发生更改、添加或删除时,问题就会变得明显。这是因为该函数将再次被调用,生成一个全新的要渲染的内容列表。如果 Markup 看到新列表,它将重新渲染所有内容。
更好的方法是不在渲染时动态映射列表,而是在创建时动态映射列表,这样 Markup 始终拥有您想要渲染的内容,以便它可以检查其是否与以前不同。
javascript
const [todos, updateTodos] = state([])
html`${todos}`.render(document.body)
updateTodos((prev) => [
...prev,
renderTodo({
name: 'Go to gym',
status: 'pending',
}),
])这正是 repeat 实用程序通过获取数据和渲染函数为您所做的事情。
数字
repeat 帮助程序接受许多事物中的一些。该数字表示您希望回调渲染函数需要被调用的次数。
javascript
html`${repeat(3, html`<spa></span>`)}`回调函数将使用从 1 到您随索引提供的数字进行调用。
javascript
html`${repeat(3, (n, index) => html`<spa>${n} - ${index}</span>`)}`.render(
document.body
)
// <span>1 - 0</span><span>2 - 1</span><span>3 - 2</span>可迭代对象和对象字面量
此外,repeat 可以使用任何对象文字或可迭代对象,这包括:
- 数组
- 套装
- 地图
- 字符串
- 具有 Symbol.iterator 的任何对象
javascript
const iterable = {}
iterable[Symbol.iterator] = function* () {
yield 1
yield 2
yield 3
}
html`${repeat(iterable, renderItem)}`由于 Markup 模板不处理渲染此类对象(数组除外),因此这是使用 repeat 的另一个优势。您不必担心将任何数据转换为数组,这样您就可以迭代和渲染。
回调函数将始终使用条目和索引来调用。
javascript
const employeesSalary = {
'john doe': 30000,
'jane doe': 54000,
}
html`${repeat(employeesSalary, ([name, salary], index) => html`...`)}`空状态
repeat 还使用一个可选的第三个参数,该函数将被调用以返回数据为空时要呈现的内容。
javascript
html`${repeat(todos, renderTodo, () => html`<p>No todos yet!</p>`)}`按键和选项
默认情况下,repeat 使用列表项本身作为身份密钥来跟踪更新。如果您的项目是对象或者您想通过唯一标识符跟踪它们,则可以传递选项对象作为第三个参数:
javascript
const options = {
key: (todo, index) => todo.id,
empty: () => html`<p>No todos yet!</p>`,
}
html`${repeat(todos, renderTodo, options)}`选项对象支持以下属性:
key(函数):一个选择器函数,为每个项目返回唯一的键。强烈推荐用于可以重新排序、添加或删除项目的动态列表。empty(函数):当集合为空时返回要渲染的模板或节点的函数。
惰性列表渲染
要优化包含大量复杂项目的列表,您可以将 repeat 实用程序与 visible 实用程序结合使用。这会推迟屏幕外列表项的渲染,直到它们即将滚动到视图中:
javascript
import { html, repeat, visible } from '@beforesemicolon/markup'
html`
<ul>
${repeat(
todos,
(todo, index) =>
visible(
() => html`<todo-item item="${todo}"></todo-item>`,
html`<li class="placeholder">Loading...</li>`,
{ eager: index < 10 } // render first 10 immediately
),
{ key: (todo) => todo.id }
)}
</ul>
`