重复实用程序

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 可以使用任何对象文字或可迭代对象,这包括:

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)}`

选项对象支持以下属性:

惰性列表渲染

要优化包含大量复杂项目的列表,您可以将 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>
`
编辑本文档