Vue Draggable实现拖拽功能的操作方法
作者:吃代码长大的前端
这是一个关于 vuedraggable 的非常详尽的指南,涵盖了如何使用它,以及它几乎所有的属性、事件、插槽和方法。
vuedraggable 是一个基于强大的 Sortable.js 库的 Vue 组件,它允许你通过拖拽的方式对列表进行排序、移动、克隆等操作,并且与 Vue 的数据响应式系统无缝集成。
1. VueDraggable 的核心概念
- 数据驱动: 你只需要管理一个数组数据,
vuedraggable会自动处理 DOM 的移动和更新。 - 基于 Sortable.js: 它继承了
Sortable.js的所有强大功能和配置选项。 - 组件化: 以 Vue 组件的形式使用,非常易于集成。
2. 如何安装和使用
A. 安装
对于 Vue 3 (推荐)
你需要安装 vuedraggable@next 版本。
npm install vuedraggable@next
对于 Vue 2
使用默认版本即可。
npm install vuedraggable
本指南将主要以 Vue 3 的 vuedraggable@next 为例,因为它代表了未来的方向。
B. 基本用法
下面是一个最简单的例子,展示了如何在一个列表中进行拖拽排序。
<template>
<div>
<h3>可拖拽列表</h3>
<draggable
v-model="myList"
item-key="id"
@start="onStart"
@end="onEnd"
>
<template #item="{element, index}">
<div class="list-item">
{{ element.name }} (ID: {{ element.id }}) - 索引: {{ index }}
</div>
</template>
</draggable>
<pre>{{ JSON.stringify(myList, null, 2) }}</pre>
</div>
</template>
<script setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';
const myList = ref([
{ id: 1, name: '苹果' },
{ id: 2, name: '香蕉' },
{ id: 3, name: '橘子' },
{ id: 4, name: '葡萄' }
]);
const onStart = (event) => {
console.log('拖拽开始', event);
};
const onEnd = (event) => {
console.log('拖拽结束', event);
// event.oldIndex - 拖拽前的位置
// event.newIndex - 拖拽后的位置
console.log(`从索引 ${event.oldIndex} 移动到 ${event.newIndex}`);
};
</script>
<style scoped>
.list-item {
padding: 10px;
margin: 5px;
background-color: #f0f0f0;
border: 1px solid #ccc;
cursor: grab;
}
.list-item:active {
cursor: grabbing;
}
</style>核心解释:
import draggable from 'vuedraggable': 引入组件。<draggable>: 这是vuedraggable的组件标签。v-model="myList": 这是最关键的部分。它将组件与你的数据数组myList双向绑定。当你在界面上拖拽排序后,myList数组的顺序会自动更新。item-key="id": 极其重要! 为了让 Vue 能够高效地跟踪和复用每个列表项,你需要提供一个唯一的key。它可以是一个字符串,指向你数组对象中唯一的属性(如id),或者是一个返回唯一值的函数。#item="{element, index}": 这是默认插槽的用法。vuedraggable会遍历你的v-model数组,并为每一项提供element(当前项的数据) 和index(当前项的索引) 作为插槽 prop,供你在模板中使用。
C. 两个列表之间拖拽
这是另一个常见场景,例如从一个"待办事项"列表拖到"已完成"列表。
<template>
<div class="two-lists">
<div>
<h3>待办事项</h3>
<draggable
v-model="list1"
item-key="id"
group="tasks"
class="list-group"
>
<template #item="{element}">
<div class="list-group-item">{{ element.name }}</div>
</template>
</draggable>
</div>
<div>
<h3>已完成</h3>
<draggable
v-model="list2"
item-key="id"
group="tasks"
class="list-group"
>
<template #item="{element}">
<div class="list-group-item">{{ element.name }}</div>
</template>
</draggable>
</div>
</div>
</template>
<script setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';
const list1 = ref([
{ id: 1, name: '写代码' },
{ id: 2, name: '测试功能' },
]);
const list2 = ref([
{ id: 3, name: '修复Bug' },
{ id: 4, name: '上线发布' },
]);
</script>
<style>
.two-lists { display: flex; gap: 20px; }
.list-group { min-height: 100px; background-color: #eee; padding: 10px; }
.list-group-item { padding: 10px; background-color: white; border: 1px solid #ddd; margin-bottom: 5px; cursor: grab; }
</style>核心解释:
group="tasks": 两个draggable组件设置了相同的group名称。这告诉vuedraggable,它们属于同一个组,元素可以在它们之间相互拖拽。
3. 所有属性 (Props)
vuedraggable 的属性主要分为两类:组件自身属性和继承自 Sortable.js 的选项。
A. 组件核心属性
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
v-model | Array | [] | 必需。用于双向绑定的数据数组。当拖拽操作完成时,此数组会自动更新。 |
item-key | String | Function | - | 必需。用于 Vue diff 算法的唯一标识。可以是对象中的属性名(如 'id')或一个返回唯一值的函数 (element) => element.id。 |
tag | String | 'div' | 指定 draggable 组件渲染的根元素标签,例如 'ul', 'tbody' 等。 |
componentData | Object | {} | 一个对象,用于向渲染的根元素(由 tag 决定)传递额外的 HTML 属性,如 class, style, id 等。 |
B. 继承自 Sortable.js 的选项 (作为 Props 使用)
这些属性直接控制拖拽的行为,非常强大。
| 属性名 | 类型 | 默认值 | 描述 |
|---|---|---|---|
group | String | Object | undefined | 用于在多个列表之间拖拽。设置为相同字符串名的列表可以互相拖拽。也可以是对象 { name: 'my-group', pull: true, put: true, pull: 'clone' } 来进行更精细的控制。 |
sort | Boolean | true | 是否允许在列表内部进行排序。 |
disabled | Boolean | false | 是否禁用整个 draggable 组件。 |
animation | Number | 150 | 拖拽动画的持续时间(毫秒)。设置为 0 则禁用动画。 |
handle | String | undefined | 指定一个 CSS 选择器(如 .drag-handle),只有拖拽这个选择器匹配的元素才能触发拖拽。 |
filter | String | undefined | 指定一个 CSS 选择器,该选择器匹配的元素将不能被拖拽(例如,输入框)。 |
ghostClass | String | 'sortable-ghost' | 拖拽时,元素在目标位置的占位符的 CSS 类名。 |
chosenClass | String | 'sortable-chosen' | 拖拽时,被选中的源元素的 CSS 类名。 |
dragClass | String | 'sortable-drag' | 拖拽时,正在被拖拽的元素的克隆体的 CSS 类名。 |
forceFallback | Boolean | false | 如果为 true,将强制使用 JS 来模拟拖拽效果(创建一个克隆元素),而不是使用原生的 HTML5 拖放 API。在某些复杂场景或 iframe 中可能需要。 |
fallbackClass | String | 'sortable-fallback' | 当 forceFallback: true 时,被拖拽的克隆元素的 CSS 类名。 |
fallbackOnBody | Boolean | false | 当 forceFallback: true 时,是否将克隆元素附加到 document.body。 |
delay | Number | 0 | 鼠标按下后需要等待多少毫秒才能开始拖拽。 |
delayOnTouchOnly | Boolean | false | 如果为 true,delay 选项仅在触摸设备上生效。 |
touchStartThreshold | Number | 0 | 触摸设备上,手指需要移动多少像素才能开始拖拽。 |
swapThreshold | Number | 1 | 拖拽元素覆盖目标元素的百分比达到多少时才进行交换(0 到 1)。 |
invertSwap | Boolean | false | 如果为 true,当拖拽元素中心越过目标元素中心时才进行交换。 |
4. 所有事件 (Events)
你可以通过 @event-name 的方式监听这些事件来执行自定义逻辑。
| 事件名 | 载荷 (Payload) | 描述 |
|---|---|---|
start | (event) | 拖拽开始时触发。event 包含 oldIndex。 |
end | (event) | 拖拽结束时触发。event 包含 oldIndex, newIndex。 |
add | (event) | 当元素从另一个列表拖拽进来时,在新列表上触发。event 包含 newIndex。 |
remove | (event) | 当元素被拖拽到另一个列表时,在旧列表上触发。event 包含 oldIndex。 |
update | (event) | 当列表内部排序发生变化时触发。event 包含 oldIndex, newIndex。 |
choose | (event) | 当一个元素被选中时触发。event 包含 oldIndex。 |
unchoose | (event) | 当一个元素被取消选中时触发。event 包含 oldIndex。 |
sort | (event) | 当列表排序发生任何变化时触发(包括 add, remove, update)。 |
change | (event) | 这是一个更通用的事件,当列表发生变化时触发。event 对象包含 added、removed 或 moved 字段,描述了具体的变化。 |
clone | (original) | 当使用 pull: 'clone' 时,在克隆元素时触发。original 是原始元素的数据。 |
move | (event, originalEvent) | 拖拽过程中每次移动都会触发。可以通过返回 false 来取消本次移动。 |
5. 所有插槽 (Slots)
| 插槽名 | 作用域变量 ({...}) | 描述 |
|---|---|---|
item | {element, index} | 默认插槽。用于渲染列表中的每一个可拖拽项。element 是当前项的数据对象,index 是当前项在数组中的索引。 |
header | - | 在列表的开头添加一个固定的、不可拖拽的区域。 |
footer | - | 在列表的末尾添加一个固定的、不可拖拽的区域。 |
插槽示例
<draggable v-model="myList" item-key="id">
<!-- 头部插槽 -->
<template #header>
<div class="header">这是列表的头部</div>
</template>
<!-- 默认/item 插槽 -->
<template #item="{element}">
<div class="list-item">{{ element.name }}</div>
</template>
<!-- 尾部插槽 -->
<template #footer>
<div class="footer">这是列表的尾部</div>
</template>
</draggable>6. 方法 (Methods)
通常情况下,你不需要直接调用 vuedraggable 的方法,因为它是数据驱动的。但在某些特殊情况下,你可能需要通过 ref 访问底层的 Sortable.js 实例。
给组件添加 ref:
<draggable ref="draggableRef" ...>
在 <script setup> 中定义 ref:
import { ref } from 'vue';
const draggableRef = ref(null);
访问 Sortable.js 实例:vuedraggable 将 Sortable.js 实例暴露在 sortable 属性上。
const sortableInstance = draggableRef.value.sortable;
现在你可以调用 Sortable.js 的原生方法,例如:
sortableInstance.toArray(): 返回一个包含所有子元素data-id的数组。sortableInstance.sort(orderArray): 根据提供的 ID 数组对列表进行排序。sortableInstance.destroy(): 销毁 Sortable 实例。
注意: 直接操作 Sortable.js 实例可能会绕过 Vue 的响应式系统,请谨慎使用。绝大多数场景都可以通过 props 和 events 来完成。
总结
vuedraggable 是一个功能强大且易于使用的库。掌握它的关键在于:
v-model和item-key是基础,必须正确设置。- 使用
group属性实现多列表交互。 - 通过 Props (如
animation,handle,ghostClass) 来定制拖拽行为和外观。 - 监听 Events (如
end,add,change) 来在拖拽操作后执行业务逻辑(例如,向服务器发送更新后的排序)。 - 利用 Slots (
item,header,footer) 来灵活地定义列表结构。
希望这份详尽的指南能帮助你完全掌握 vuedraggable!
到此这篇关于Vue Draggable实现拖拽功能的文章就介绍到这了,更多相关Vue Draggable拖拽内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
