Svelte:在“each”块内使用“bind:this”

Mar*_*.H. 8 svelte

我想使用块来渲染对象数组each。我需要能够使用块内部的回调从数组中删除元素each。此外,对于更复杂的 UI 交互,我需要each在主应用程序中提供对块的每个组件的引用。

这是我的方法:

<script>
    let items = [{text: "one"}, {text: "two"}];
    
    function deleteItem(i) {
        items.splice(i, 1);
        items = items;
    }
</script>

{#each items as item, i}
<button bind:this={items[i].ref} on:click={() => deleteItem(i)} >
    {item.text}
</button>   
<p />
{/each}
Run Code Online (Sandbox Code Playgroud)

可以理解,这会导致诸如 之类的错误item[i] is undefined,因为在处理 的拼接时itemsbind:this无法再正确清理。

我尝试通过将组件引用移动到单独的数组来解决这个问题。但无论我尝试什么,我都无法使引用数组和对象数组同步:每当处理时,我都会在数组内deleteItem()得到-值。这是我的方法之一(打印-array 的 -section 应该有助于显示 -values ):nullrefseachrefsnull

<script>
    import {tick } from "svelte";
    let items = [{text: "one", id: 1}, {text: "two", id:2}];
    let refs = [];
    
    async function deleteItem(i) {
        items.splice(i, 1);
        await tick();
        refs.splice(i, 1);
        items = items;
        console.log(refs);
    }
</script>

{#each items as item, i (item.id)}
<button on:click={async () => deleteItem(i)} bind:this={refs[i]}>
    {item.text}
</button>   
<p />
{/each}

{#each refs as ref}
{ref}
<p />
{/each}
Run Code Online (Sandbox Code Playgroud)

我尝试了 with 和 without tick(),尝试在不同的地方插入,在每个块中tick()使用和不async使用以及使用和不使用。(item.id)如何保持参考文献和数据同步?

Ste*_*aes 11

解决这个问题的方法是在refs使用数组之前清理它:

<script>
 let items = [...]
 let _refs = []
 $: refs = _refs.filter(Boolean)
</script>

<button bind:this={_refs[i]}></button>
Run Code Online (Sandbox Code Playgroud)

使用此技术,您仍将拥有null原始_refs数组中的值,但复制的版本 ( refs ) 将是干净的。

另一种方法是将元素绑定到项目本身,但如果您也在其他地方使用该数据,则可能不需要这样做:

<button bind:this={item.ref}>
Run Code Online (Sandbox Code Playgroud)

(请注意,这仍然会产生错误,因为绑定元素在切片期间消失,但​​仅通过赋值进行处理,您可以通过使用过滤器语句进行切片和赋值来解决这个问题)

items = items.filter((item, idx) => idx != i)
Run Code Online (Sandbox Code Playgroud)