Vue Draggable Plus 入门:拖拽排序最佳实践
待办列表拖一下换位置、后台菜单拖一下调顺序——这类交互用户已经默认「就该有」。Vue Draggable Plus 让它变成三行代码。
它是什么
Vue Draggable Plus 是 Vue 3 的拖拽排序组件库,基于原生 HTML5 Drag and Drop API 实现(底层用了 SortableJS 的成熟方案),提供两种用法:组件包裹式(VueDraggable)和组合式函数式(useDraggable)。
它解决的痛点:原生的拖放 API 极其底层(dragstart/dragover/drop 事件、dataTransfer 传递、防默认行为),自己实现一个「拖动重排列表」要写上百行代码还要处理各种边界。这个库把「拖动 → 目标位置计算 → 数据顺序更新」整个封装掉了。
pnpm add vue-draggable-plus
最小示例:拖动排序一个列表
组件式——直接包住要排序的元素:
<script setup>
import { ref } from 'vue';
import { VueDraggable } from 'vue-draggable-plus';
const list = ref([
{ id: 1, title: '学 Vue 3' },
{ id: 2, title: '学 Pinia' },
{ id: 3, title: '写项目' },
]);
function onUpdate() {
// 拖动结束时 list.value 的顺序已经是新的了,直接保存即可
saveOrder(list.value.map((item, i) => ({ id: item.id, sort: i })));
}
</script>
<template>
<VueDraggable v-model="list" @update="onUpdate" class="task-list">
<div v-for="item in list" :key="item.id" class="task-item">
{{ item.title }}
</div>
</VueDraggable>
</template>
核心心智模型:v-model 绑定数组,拖动后数组顺序自动更新。你不需要知道拖到了第几位——数据就是真相,DOM 跟随数据。
函数式——不引入组件,给已有元素附加拖拽能力:
<script setup>
import { ref } from 'vue';
import { useDraggable } from 'vue-draggable-plus';
const list = ref([...]);
const el = ref(null);
useDraggable(el, list, { animation: 150 });
</script>
<template>
<ul ref="el">
<li v-for="item in list" :key="item.id">{{ item.title }}</li>
</ul>
</template>
函数式适合「列表结构不想被组件包一层」的场景(比如表格行排序),组件式适合常规列表。两者能力一致。
常用配置
useDraggable(el, list, {
animation: 150, // 拖动动画时长,体验必需
handle: '.drag-icon', // 只允许通过把手拖动(内容区还能正常选中文字)
filter: 'input', // 元素内 input 不可触发拖拽
ghostClass: 'drag-ghost', // 拖动中占位符的样式类
chosenClass: 'drag-chosen', // 被选中项样式
disabled: readonly, // 响应式开关:查看态禁拖、编辑态可拖
});
handle 值得单独说:不要让整个卡片可拖。用户想选中卡片里的文字、点卡片里的按钮,全被拖拽拦截,体验很糟。给一个显式的拖拽把手(六点图标)才是对的交互。
跨列表拖动
两个列表之间互拖(回收站还原、任务看板列间移动),把同一个 group 名配给两个 draggable 即可:
<VueDraggable v-model="todoList" group="tasks" @add="onAddTodo">
<TaskItem v-for="t in todoList" :key="t.id" :task="t" />
</VueDraggable>
<VueDraggable v-model="doneList" group="tasks" @add="onAddDone">
<TaskItem v-for="t in doneList" :key="t.id" :task="t" />
</VueDraggable>
@add 在元素从别的列表拖进来时触发,v-model 的数组已经包含了新成员,你要做的是同步后端(改它的状态字段)。
本站的应用
本站管理后台里 Wiki 目录排序、待办清单排序用的就是它:目录树里拖动条目调整顺序,拖完把新的顺序(id + sort 值列表)一次性提交后端。交互上配了 handle 把手 + animation: 150,拖动时有幽灵占位提示落点。
与后端配合的正确姿势
拖拽排序的前端很爽,后端要接得住。通用方案:每个条目存一个 sort 整数字段,拖完把全量顺序(或受影响区间的 id→sort 映射)提交,后端一个事务批量更新。条目量大时用间隔数值(如 1000、2000、3000)留插队余量,减少每次拖动要更新的行数。
小结
Vue Draggable Plus 把「拖拽排序」从一天的工作量压缩到三行代码,且通过 v-model 保持了「数据驱动」的 Vue 心智——你不操作 DOM,只操作数组。记住两个细节:配 handle 把手保护交互区,拖完提交 sort 让顺序持久化。