Vue 3拖拽排序分原生API和vuedraggable两类:原生需手动管理dragstart存索引、dragover/dragenter仅.prevent、drop执行splice重排;vuedraggable推荐用于业务,用v-model绑定,@update处理排序逻辑,@end用于收尾清理。

在 Vue 3 中实现拖拽排序列表时,绑定拖拽开始、经过和结束事件,核心是围绕 HTML5 原生拖放 API(dragstart、dragover、drop 等)或封装好的第三方库(如 vuedraggable 或 SortableJS)来组织逻辑。不同方案事件名和触发时机有差异,下面分两类说明,直接对应开发场景:
原生 draggable + Vue 3 响应式逻辑
适用于轻量、可控、不依赖额外包的场景。需手动管理索引与数据重排。
-
@dragstart:记录被拖项索引,并设置拖拽数据const dragIndex = ref(null); const handleDragStart = (index) => { dragIndex.value = index; event.dataTransfer.setData('text/plain', index); // 必须设,否则 drop 可能无效 }; -
@dragover.prevent和@dragenter.prevent:仅阻止默认行为,让drop可触发(二者常同时加.prevent)立即学习“前端免费学习笔记(深入)”;
注意:
dragover会高频触发(约每 100ms 一次),不能在其中做数组操作,只用于“标记可放置区域”或视觉反馈。 -
@drop:真正执行位置交换的时机const handleDrop = (targetIndex) => { if (dragIndex.value === null || dragIndex.value === targetIndex) return; const item = list.value.splice(dragIndex.value, 1)[0]; const insertIndex = dragIndex.value < targetIndex ? targetIndex - 1 : targetIndex; list.value.splice(insertIndex, 0, item); dragIndex.value = null; // 重置 };
✅ 关键点:
dragstart存索引、dragover/dragenter仅.prevent、drop执行重排。不要用dragend更新数据——它不提供目标位置信息。
使用 vuedraggable(推荐用于业务项目)
基于 SortableJS 封装,事件更语义化、支持嵌套/动画/跨容器等,且自动同步数据。
-
@start:拖拽刚开始,DOM 元素被拿起const onStart = () => { console.log('拖拽已开始'); }; -
@move:拖拽过程中实时判断是否允许放置到某位置(返回false则禁止)const onMove = (evt) => { // evt.draggedContext.index: 当前拖拽项原索引 // evt.relatedContext.index: 目标位置索引(hover 的项) return evt.draggedContext.index !== evt.relatedContext.index; }; -
@end:拖拽完全结束(无论是否发生位置变化)const onEnd = ({ oldIndex, newIndex }) => { if (oldIndex !== newIndex) { console.log(`从 ${oldIndex} 移动到 ${newIndex}`); // 数据已自动更新,无需手动 splice } }; -
其他实用事件:
-
@add:元素被拖入新列表(跨列表) -
@update:列表内顺序变更(最常用,比@end更精准) -
@choose:元素刚被选中(可用于添加高亮 class)
-
✅ 关键点:
v-model双向绑定数据,@update是处理排序后逻辑的首选;@end更适合收尾清理(如移除 loading 状态)。
不复杂但容易忽略


















