如何实现一个拖拽排序前言 拖拽效果呢在我们日常是很常见的一个效果,例如底代码的开发,管理系统内的用户拖动排序等效果,那么
前言
拖拽效果呢在我们日常是很常见的一个效果,例如底代码的开发,管理系统内的用户拖动排序等效果,那么我们如何自己是先一个拖拽排序的效果呢,以及有哪些比较好用的拖拽库,下面我们一起了解一下
简单实现
首先我们先自己了解一下应该如何实现一个拖拽排序的效果,实现拖拽排序呢主要使用到了以下个API,draggable
开启拖拽功能,dragstart
拖拽开始(只在开始时执行一次),dragover
拖拽中(会在拖拽的时候一直执行直到拖拽结束),dragend
拖拽结束(接收拖拽后执行一次)。
我们知道了要使用到这些API那么具体如何实现呢。其实拖拽排序就是数组内的某一个元素从A位置变换到了B位置,那么我们只需要开始拖拽的时候拿到这个拖拽的元素现在的位置,然后再拖拽中拿到拖拽到的位置对其进行一个插入就可以了。
<script setup lang="ts">
import { ref } from 'vue'
// 高亮下标
const activeIndex = ref(-1)
// 列表数据
const list = ref([
{ id: 3, name: 'one' },
{ id: 4, name: 'two' },
{ id: 5, name: 'three' },
{ id: 6, name: 'Four' },
{ id: 7, name: 'Five' },
])
// 拖拽开始
const onDragStart = (index: number) => {
// 更新下标
activeIndex.value = index
}
const onDragOver = (index: number) => {
console.log(index)
// 提取数据
const draggingItem = list.value.splice(activeIndex.value, 1)
// 添加数据
list.value.splice(index, 0, ...draggingItem)
// 更新下标
activeIndex.value = index
}
const onDragEnd = () => {
// 恢复下标
activeIndex.value = -1
}
</script>
<template>
<div class="list">
<div
class="item"
v-for="(item, index) in list"
:key="item.id"
:draggable="true"
@dragstart="onDragStart(index)"
@dragover="onDragOver(index)"
@dragend="onDragEnd">
{{ item.name }}
</div>
</div>
<pre class="data">{{ list }}</pre>
</template>
具体实现逻辑如上,首先开始拖拽的时候我们拿到拖拽的下标,然后再拖拽进行的时候拿到拽到到哪里的下标,然后使用splice
截取掉拖拽的这个元素,再插入到当前拿到的下标的地方。splice
会影响原数组,所以相当于是再拖拽的时候把这个拖拽的元素删除了,然后再拖拽到的位置上再动态进行了插入。
vuedraggable
上面我们实现了简单的拖拽排序效果,但是在日常开发中可能有更复杂的需求,那么我们就可以使用到vuedraggable
来进行实现,他使用起来更加的方便,也有一些自己的事件
<template>
<draggable :list="list" class="list" animation="300" @start="onStart" @end="onEnd" itemKey="id">
<template #item="{ element }">
<div class="item">
{{ element.name }}
</div>
</template>
</draggable>
<pre class="data">{{ list }}</pre>
</template>
只需要下载插件进行简单的配置就可以实现我们上面的效果,animation
来实现动画效果,还有我们的开始事件和结束事件,还可以进行筛选是否允许拖动 如:filter=".unmover"
设置了unmover
不允许拖动
拖拽分配
我们在开发的时候可能会有任务分配的功能,或者是任务列表拖拽改变状态的效果,下面我们继续使用上面的例子开扩展,做一个任务分配的效果
<div class="group">
总任务
<draggable class="list" v-model="list1" item-key="id" :group="{ name: 'task' }">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
A
<draggable class="list" v-model="list2" item-key="id" :group="{ name: 'task' }">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
B
<draggable class="list" v-model="list3" item-key="id" :group="{ name: 'task' }">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
</div>
这样就实现了一个简单的任务分配的效果,主要呢就是配置group
拥有相同的name,那么就可以进行相互拖拽分配
克隆
我们在底代码上进行拖拽生成的时候,只可以从左侧拖拽到编辑区,但是不能从编辑区拖拽到左侧,并且从左侧拖拽出去的左侧的应该还存在,这个呢我们就要用到了克隆的属性,具体如下
<draggable
class="list"
v-model="list1"
item-key="id"
:group="{ name: 'task', pull: 'clone', put: false }"
>
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
只需要设置pull
为clone
,put
为false
,那么就实现了类似于底代码里的那种效果,可以拖出去,但是不能拖进来,并且左侧拖出去的是复制了一份到其他列表
简易版底代码效果
我们看来上方的一些属性现在就可以实现一个简单版本的底代码的效果了,只不过上面我们用到的是渲染数据,这里我们是做组件的渲染。
<script setup lang="ts">
import { ref } from "vue";
import draggable from "vuedraggable";
// 需要使用ref
const list1 = ref([
{
id: 1,
tag: "el-button",
props: {
type: "primary",
},
text: "按钮",
},
{
id: 2,
tag: "el-input",
props: {
placeholder: "请输入内容",
},
},
{
id: 3,
tag: "el-switch",
},
]);
// 组件数据列表
const list2 = ref([]);
</script>
<template>
<el-container class="container">
<el-aside class="aside" width="200px">
<draggable
class="list"
v-model="list1"
item-key="id"
:group="{ name: 'component', pull: 'clone', put: false }"
:sort="false"
>
<template #item="{ element }">
<div class="item">
{{ element.tag }}
</div>
</template>
</draggable>
</el-aside>
<el-main class="main">
<draggable
v-model="list2"
item-key="id"
class="content"
:group="{ name: 'component' }"
>
<template #item="{ element }">
<div class="component">
<!--
is: 组件名
v-bind: 动态 props
-->
<component :is="element.tag" v-bind="element.props">
{{ element.text }}
</component>
</div>
</template>
</draggable>
</el-main>
</el-container>
</template>
<style scoped lang="scss">
.container {
display: flex;
}
.aside {
background-color: pink;
}
.main {
flex: 1;
height: 100vh;
background-color: skyblue;
.content {
background-color: #fff;
height: 100%;
}
}
.list {
.item {
border: #0083ee 1px solid;
margin: 10px;
padding: 10px;
}
}
</style>
我们在左侧面板的list内定义好属性和组件名称,然后在右侧呢使用component
来渲染组件,使用v-bind
传入一些属性,这样就实现了一个简易版本的底代码拖拽的一个效果
结尾
我们日常可能不太会使用到底代码的这种拖拽,用的比较多的可能还是拖拽排序,拖拽分组这样的效果。 这里主要就是了解一下如何实现一个拖拽排序的效果,以及vuedraggable
插件的一个用法
转载自:https://juejin.cn/post/7415651555120005154