在vue项目中使用draggable 拖拽组件来拖动排序
正常使用代码如下:
<template>
<draggable
v-model="draggableList"
:tag="tag"
:scroll="true"
:filter="filter"
:move="() => true"
:animation="animation"
item-key="id"
@end="endCallback"
>
<!-- 这里是拖拽的内容 -->
<template #item="{ element }">
<div class="px-6px cursor-pointer my-6px hover-bg-#f2f2f2" :class="{ filterClass: element.id === 3 }">
<!-- 坑:拖拽的div css 样式不要为position relative ,否则无法使用 -->
<span>{{ element.label }}</span>
<n-icon class="ml-6px text-12px" @click="handleDelete(element.id)">
<svg
t="1659758644821"
class="icon"
viewBox="0 0 1024 1024"
version="1.1"
xmlns="http://www.w3.org/2000/svg"
p-id="2402"
>
<path
d="M218.496 846.933333a42.666667 42.666667 0 0 1-60.330667-60.373333l272.170667-272.170667L177.066667 261.162667a42.666667 42.666667 0 0 1 60.330666-60.330667l253.226667 253.226667 270.933333-270.933334a42.666667 42.666667 0 0 1 60.288 60.373334l-270.890666 270.933333 289.834666 289.792a42.666667 42.666667 0 1 1-60.330666 60.330667L490.666667 574.762667l-272.170667 272.128z"
p-id="2403"
></path>
</svg>
</n-icon>
</div>
</template>
</draggable>
</template>
<script lang="ts" setup>
import { ref } from 'vue';
import draggable from 'vuedraggable';
const tag = 'div'; // 拖拽框父盒子会是tbody,写其它标签,如div,则父盒子为div
const filter = '.filterClass'; // 有这个类名则不可拖拽
const animation = 200; // 拖拽变化的时候有个200秒的变化动画
// 拖拽的列表
const draggableList = ref([
{ label: '零--------------零', id: 0 },
{ label: '一--------------一', id: 1 },
{ label: '二--------------二', id: 2 },
{ label: '三---disabledraggable---三', id: 3 },
{ label: '四--------------四', id: 4 },
{ label: '五--------------五', id: 5 },
{ label: '六--------------六', id: 6 }
]);
function endCallback(e: { newIndex: number; oldIndex: number }) {
// 穿梭框拖动会自动改变位置,如果想手动改变,可以这样,将新的位置和旧的位置进行替换
// const { newIndex, oldIndex } = e;
// const tempIndex = draggableList.value.splice(oldIndex, 1)[0];
// draggableList.value.splice(newIndex, 0, tempIndex);
}
// 移除拖拽项
function handleDelete(id: string) {
const index = draggableList.value.find(item => item.id === id);
draggableList.value.splice(index, 1);
}
</script>
上面要注意可能会踩的两个坑
1. 拖拽数据移动顺序错乱,可能是因为绑定的列表,在拖拽完成之后,被其它函数改变了,可以在end 函数里面打断点排查
2.每行数据的值的外层元素不能设置position为relative,否则会出现无法拖动的情况
使用 h 函数如下
html:
<render-draggable />
js:
const renderDraggable = h(
draggable,
{
class: 'px-4px',
scroll: true,
itemKey: 'id',
tag,
filter,
modelValue: draggableList.value,
move: () => {
return true;
},
onEnd: endCallback
},
{
item: ({ element }: { element: IProjectItem }) => {
return h(
'div',
{
class: `px-6px cursor-pointer my-6px hover-bg-#f2f2f2 ${element.id === 3 ? 'filterClass' : ''}`
},
{
default: () => {
return [
h('span', {}, element.label),
h(
NIcon,
{ class: 'ml-6px text-12px' },
{
default: () =>
h(
'svg',
{
t: '1659758644821',
class: 'icon',
viewBox: '0 0 1024 1024',
version: '1.1',
xmlns: 'http://www.w3.org/2000/svg',
pId: '2402'
},
{
default: () =>
h('path', {
d: 'M218.496 846.933333a42.666667 42.666667 0 0 1-60.330667-60.373333l272.170667-272.170667L177.066667 261.162667a42.666667 42.666667 0 0 1 60.330666-60.330667l253.226667 253.226667 270.933333-270.933334a42.666667 42.666667 0 0 1 60.288 60.373334l-270.890666 270.933333 289.834666 289.792a42.666667 42.666667 0 1 1-60.330666 60.330667L490.666667 574.762667l-272.170667 272.128z',
pId: '2403'
})
}
)
}
)
];
}
}
);
}
}
);
function endCallback(e: { newIndex: number; oldIndex: number }) {
// 穿梭框拖动会自动改变位置,如果想手动改变,可以这样,将新的位置和旧的位置进行替换
const { newIndex, oldIndex } = e;
const tempIndex = draggableList.value.splice(oldIndex, 1)[0];
draggableList.value.splice(newIndex, 0, tempIndex);
}
更多功能,可看中文文档,可以实现一些复杂的场景,如两个列表之间的拖动、表格的行列拖动等
有两个版本
2.plus 版本VueDraggablePlus | 支持 Vue2 和 Vue3 的拖拽组件vue3拖拽排序组件https://alfred-skyblue.gitee.io/vue-draggable-plus/