You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Svelte结合SortableJS处理动态数组时列表异常问题求助

解决Svelte + SortableJS多列表拖拽的卡顿/数据同步问题

问题根源

  1. #each循环缺少唯一key:Svelte无法准确跟踪列表项的DOM元素,拖拽后重渲染时出现元素错位、重复的问题。
  2. 拖拽事件处理不当:原代码用onSort事件,该事件会在拖拽过程中多次触发,且只更新了目标数组,未从源数组移除拖拽元素,导致数据和DOM状态不一致。
  3. 响应式更新触发不及时:直接修改数组内部元素时,Svelte可能无法检测到父级数组的变化,导致视图不同步。

修复方案

1. 给App.svelte的列表项添加唯一key

在遍历分类内的元素时,加上(item.id)作为key,让Svelte精准识别每个元素:

<script>    
    import List from "./List.svelte";
    let items = [
        [
            {id: 1,name: "one"},
            {id: 2,name: "two"},
        ],
        [
            {id: 3,name: "three"},
            {id: 4,name: "four"},
        ]
    ]
</script>

{#each items as category, i}
    <h2>Category {i}</h2>
    <ul>
        <List bind:fullArr={items} index={i}>
            <!-- 添加(item.id)作为唯一key -->
            {#each category as item (item.id)}
                <li data-id={item.id} >{item.name}</li>
            {/each}
        </List>
    </ul>
{/each}

{JSON.stringify(items)}

2. 重写List.svelte的拖拽事件逻辑

改用onEnd事件(拖拽完成后仅触发一次),通过事件参数获取源/目标列表信息,正确修改两个数组,并确保触发Svelte的响应式更新:

<script>
    import Sortable from 'sortablejs';
    import { onMount } from 'svelte';

    export let fullArr;
    export let index;

    let list;
    let sortable;

    onMount(() => {
        sortable = new Sortable(list, {
            group: "list",  
            // 用onEnd替代onSort,确保只在拖拽完成后处理数据
            onEnd: handleDragEnd,
        });
    })

    function handleDragEnd(evt) {
        const { from, to, oldIndex, newIndex } = evt;
        // 从DOM结构中获取源分类和目标分类的索引
        const sourceCategoryIndex = Array.from(from.parentElement.parentElement.children).indexOf(from.parentElement);
        const targetCategoryIndex = Array.from(to.parentElement.parentElement.children).indexOf(to.parentElement);

        // 从源分类数组中移除拖拽元素
        const draggedItem = fullArr[sourceCategoryIndex].splice(oldIndex, 1)[0];
        // 将元素插入目标分类数组的对应位置
        fullArr[targetCategoryIndex].splice(newIndex, 0, draggedItem);

        // 重新赋值数组触发Svelte响应式更新
        fullArr = [...fullArr];
    }
</script>

<div bind:this={list}>
    <slot></slot>
</div>

关键修改说明

  • 唯一key:让Svelte避免不必要的DOM销毁和重建,保证拖拽后视图更新准确。
  • onEnd事件:仅在拖拽完成后处理数据,避免多次触发导致的重复更新。
  • 数组操作:用splice直接修改源/目标数组,最后通过展开运算符创建新数组,强制Svelte检测到数组变化,完成视图同步。

内容的提问来源于stack exchange,提问作者Matt Thornton

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 22:22:53