javascript - 当 Svelte 重用父 dom 元素时如何确保仅本地转换
问题描述
在 Svelte 中,我有一个组件用于在两个不同的列表中显示项目。当这些项目从一个列表移动到另一个列表时,它们会使用过渡来动画进出。
但是,我也有办法过滤屏幕上显示的内容。显示一组新项目将使用相同的组件,但具有不同的数据。在这种情况下,我不希望出现过渡动画。我认为添加local
修饰符可以解决问题,但似乎 Svelte 并未将父元素删除到列表中,而是重用它并在现有列表 DOM 元素中添加新数据。
我试图重现我在下面的示例代码中看到的内容。
通缉行为:
- 单击 TODO 会将 TODO 从一个列表切换到另一个列表。
- 单击“切换类别”将切换列出哪些 TODO,而不会对
<li>
添加或删除的 TODO 进行动画处理。
实际行为:
- 按预期发生。
- 切换的待办事项与动画一起执行。
我怎样才能改变我的例子,以获得我想要的效果?
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>
解决方案
更新
自 v3.28.0 以来,此关键功能现在是 Svelte 的一部分(请参阅问题)。
语法如下:
{#key expression}...{/key}
上一个答案
在 React 中,你可以使用key
prop 让渲染器重新创建一个可以重用的元素(相同的标签等)。
// React
<Todos items={items} key={currentCategory} />
但是 Svelte 不支持key
,是吗?嗯,有点。Svelte 确实具有等效的功能,但仅限于{#each ...}
块中。
语法是这样的(文档——文档中没有提到这种精确的语法,但我想它刚刚被遗忘了):
{#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}
呼呼。正确的?
每次类别更改时,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 中的示例。
推荐阅读
- java - CrudRepository 接口 - 找不到 bean
- google-cloud-platform - 在 GCP 上配置 HTTPS 负载平衡器时,后端服务中的几个 VM 实例运行状况不佳
- spring-boot - 使用 Schema Registary 和 Kafka Restproxy 向 Kafka 发送消息的 Rest 模板
- python - 为什么当我尝试删除特定行时我的价格列被替换?
- r - 将包含分号的excel公式转换为ar公式
- ldap - 是否可以通过 HTTP 代理向 LDAP 服务器发送请求?
- c++ - 将复杂的非原始 C++ 数据类型转换为 Erlang/Elixir 格式,以使用 NIF 导出方法
- javascript - JS中导入的函数名与当前模块函数名冲突
- android - 没有文本 R.string 链接可能?字符串 [] 名称 = {};
- python-3.x - 最高效的 one-hot-encoder