本文详解如何在 svelte 中结合 sortablejs 实现多列表(嵌套数组)的稳定拖拽排序,重点解决因 `#each` 缺失 key 导致的 ui 错乱、状态不同步及双渲染问题,并提供基于 action 的简洁、可维护实现方案。
在 Svelte 中集成 SortableJS 实现跨列表拖拽时,常见“抖动”“回跳”“重复移动”等异常行为,根本原因往往不是 SortableJS 本身,而是 Sv
elte 的响应式更新机制与 DOM 状态未对齐。最典型的问题是:{#each} 块缺少唯一 key 表达式,导致 Svelte 无法准确追踪每个
✅ 正确做法:始终为 {#each category as item} 添加 key —— 使用 item.id(或其他稳定唯一标识):
{#each category as item (item.id)}
不加 (item.id) 会导致 Svelte 按索引位置比对元素,而拖拽会改变索引顺序,造成 DOM 节点被错误移动或重渲染,进而干扰 SortableJS 的内部状态。
更进一步,避免将 Sortable 初始化封装进独立组件(如 List.svelte)。自定义组件会引入额外的生命周期、作用域和响应式绑定复杂度,容易引发 fullArr[index] 赋值后视图未及时同步、onSort 多次触发、或 sortable.toArray() 返回旧 ID 序列等问题。
推荐采用 Svelte Action(use: 指令) —— 它天然与 DOM 元素绑定,生命周期清晰(仅在元素挂载/卸载时执行),且逻辑集中、无状态泄漏风险。以下是生产就绪的实现:
{#each items as category, i}
Category {i}
{JSON.stringify(items, null, 2)}? 关键要点:
通过 key 化 #each 和 action 驱动的精准状态管理,即可彻底告别“抖动列表”,构建出响应迅速、逻辑清晰、易于扩展的 Svelte 多列表拖拽系统。