在Svelte中,我有一个组件,用于显示两个不同列表中的项目。当这些项目从一个列表移到另一个列表时,它们会使用过渡效果来动画化。
但是,我也有一种方法可以过滤屏幕上显示的内容。显示一组新项目将使用相同的组件,但使用不同的数据。在这种情况下,我不希望出现过渡动画。我以为添加local
修饰符可以解决问题,但是Svelte似乎并没有将父元素拖放到列表中,而是重新使用了它,并将新数据添加到现有列表DOM元素中。 >
我试图重现下面的示例代码中看到的内容。
想要的行为:
<li>
设置动画。实际行为:
如何更改示例,以获得想要的效果?
App.svelte:
<script>
import Todos from './Todos.svelte';
let todos = [
{ id: 1, category: 'personal', name: 'Walk dog', done: false },
{ id: 2, category: 'personal', name: 'Take out trash', done: false },
{ id: 3, category: 'work', name: 'Make login page functional', done: false },
{ id: 4, category: 'work', name: 'Make login page elegant', done: false }
];
let currentCategory = 'personal';
const toggleCategory = () => {
currentCategory = currentCategory == 'personal' ? 'work' : 'personal';
}
const toggleTodo = id => {
todos = todos.map(todo => {
if (todo.id === id) {
return { ...todo, done: !todo.done }
}
return todo;
});
}
$: categoryTodos = todos.filter(x => x.category == currentCategory);
</script>
<button on:click={toggleCategory}>Switch Categories</button>
<Todos todos={categoryTodos} {toggleTodo}>
</Todos>
Todos.svelte:
<script>
import { slide } from 'svelte/transition';
export let todos;
export let toggleTodo;
$: complete = todos.filter(t => t.done);
$: incomplete = todos.filter(t => !t.done);
</script>
<h1>Incomplete</h1>
<ul>
{#each incomplete as {id, name} (id)}
<li transition:slide|local on:click={() => toggleTodo(id)}>{name}</li>
{/each}
</ul>
<h1>Complete</h1>
<ul>
{#each complete as {id, name} (id)}
<li transition:slide|local on:click={() => toggleTodo(id)}>{name}</li>
{/each}
</ul>
答案 0 :(得分:2)
在React中,您将使用key
道具来使渲染器重新创建可能已被重复使用的元素(相同的标记等)。
// React
<Todos items={items} key={currentCategory} />
但是Svelte不支持key
,对吗?好吧,有点。 Svelte确实具有等效功能,但仅在{#each ...}
块中。
语法是这样的(docs-文档中没有提到这种精确的语法,但是我想它只是被忘记了):
{#each expression as name (key)}...{/each}
就像在React中一样,当键的值更改时,组件将被重新创建(否则将被重用)。
然后...
<script>
export let allItems
export let currentCategory
$: items = allItems.filter(x => x.category === currentCategory)
</script>
{#each [items] as todos (currentCategory)}
<Todos {todos} />
{/each}
Hu。对吧?
每次更改类别时,使用currentCategory
作为键将创建一个新的<Todos />
组件。
就像在React中一样,必须明智地选择键的值以在每次需要时重新创建,但不要更多(否则,在您的情况下它会杀死所需的项间过渡)。
键的值不限于每个循环中当前评估的项。它可以来自Svelte范围内的任何地方,因此您可以发挥创造力。它甚至可能是一个内联对象{}
,它将重新创建...好吧,基本上一直如此!
修改
您可以将hack转变成自己的组件,以使使用者的语法更简洁:
<!-- Keyed.svelte -->
<script>
export let key
// we just need a 1-length array
const items = [0]
</script>
{#each items as x (key)}
<slot />
{/each}
像这样使用:
<script>
import Keyed from './Keyed.svelte'
export let items
export let category
</script>
<Keyed key={category}>
<Todos {items} />
</Keyed>
请参见Svelte的REPL中的example。