如何在虚拟列表中保留Svelte组件的状态?

时间:2018-10-05 10:01:49

标签: javascript svelte virtualscroll

我正在Svelte中开发一个甘特图组件,它由100多个行组件组成,每个行组件都包含多个任务组件。可以拖动和移动任务。性能是重中之重,我使用虚拟列表仅呈现可见行。

<div class="scrollable">
    {#each visibleRows as row (row.id)}
        <div class="row">
            {#each row.tasks as task (task.id)}
                <Task from={task.from} to={to}/>
            {/each}
        </div>
    {/each}
</div>

问题是当我四处移动任务并从视图中滚动出行时,它们将被销毁,而当我滚动回到它们时,它们的状态将被重置。这个使用svelte-virtual-list的REPL说明了问题https://svelte.technology/repl?version=2.13.5&gist=bdb4c523d2e1cf7e3aef452e3f24d988 我想知道解决这种情况的最佳方法是什么。

当前,我使用任务对象作为道具并对其进行更新,引用保持不变,并且滚动不会影响它。

<Task {task}/>

但是在Task中,我这样更新状态

const {task} = this.get();
task.from = new Date();
this.set({task});

并且模板引用了每个带有task.propname的道具,我不确定这是否是一种精巧的方法,因为不清楚确切设置了什么。

我可以像这样绑定任务变量

<Task bind:from=task.from 
      bind:to={task.to}/>

但是很多变量需要绑定(超过10个),我希望以后的插件可以从Task组件内部更新新道具。

<Task {task} 
      {...task}/>

这处理了更多的道具,但是我在状态事件中像这样更新了任务对象:

onstate({ changed, current, previous }) {
    const {task} = this.get();
    Object.assign(task, current);
    this.set({task});
},

在性能方面,我应该更喜欢其中哪些?或者有更好的方法来处理此问题?

1 个答案:

答案 0 :(得分:1)

您应该更改数据数组,而不是使对象变异。通过对数组内的对象进行突变,Svelte不知道您的数组已更改。

使用Svelte v3并使用存储而不是纯数组来更改数组将类似于以下内容:

// data.js
...
import { writable } from 'svelte/store';

export default writable(getData())
...

// App.svelte
<script>
...
import items from './data.js';

function updateContent(item) {
    const index = $items.indexOf(item)
    $items = [
        ...$items.slice(0, index),
        { ...item, content: 'updated content' },
        ...$items.slice(index + 1)
    ]
}
...
</script>

<VirtualList items={$items} let:item bind:start bind:end>
    ...
        <button on:click={() => updateContent(item)}>update content</button>
    ...
</VirtualList>

完整示例:https://svelte.dev/repl?version=3.0.0-beta.28&gist=f8c7e96bb34906db2c3a5e85b4840017

您可以在此处了解有关更新数组和对象的更多信息:https://svelte.dev/tutorial/updating-arrays-and-objects