1.使用html5标签的dragstart、dragover、dragend实现一个简单的拖拽效果
vue3测试代码如下:
<template>
<div>
<div class="list">
<!-- draggable 属性是HTML5中的一个属性,它用于定义元素是否可以被拖动,
dragstart当用户开始拖动可拖动元素时触发,
dragover当拖动元素进入潜在的拖放目标区域时触发,
dragend当拖动操作完成,拖动元素被放置或取消拖动时触发-->
<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>
</div>
</template>
<script setup >
import { ref } from 'vue'
// 记录拖拽的那个元素索引
const activeIndex = ref(null)
// 列表数据
const list = ref([
{ id: 3, name: '张三' },
{ id: 4, name: '李四' },
{ id: 5, name: '王五' },
{ id: 6, name: '赵六' },
{ id: 7, name: '田七' },
])
// 拖拽开始
const onDragStart = (index) => {
// 更新下标
activeIndex.value = index
}
//拖拽中
const onDragOver = (index) => {
// 提取数据
const draggingItem = list.value.splice(activeIndex.value, 1)
// 添加数据
list.value.splice(index, 0, ...draggingItem)
// 更新下标
activeIndex.value = index
}
//拖拽结束
const onDragEnd = () => {
// 恢复下标
activeIndex.value = null
}
</script>
<style lang="scss" scoped>
.list {
width: 500px;
border: 1px solid #000;
.item {
box-sizing: border-box;
width: 100%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
// 隔行变色
&:nth-child(even) {
background: #32a441;
}
&:nth-child(odd) {
background: rgb(218, 11, 46);
}
}
}
.data {
box-sizing: border-box;
padding: 20px;
width: 500px;
border: 1px solid #000;
font-family: serif;
}
</style>
效果如下:
2. 使用插件vuedraggable@next实现一个简单的拖拽效果
安装依赖 npm i vuedraggable@next
使用 draggable
组件
vue3测试代码如下:
<template>
<div>
<draggable class="list" v-model="list" item-key="id">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
<pre class="data">{{ list }}</pre>
</div>
</template>
<script setup >
import { ref } from 'vue'
import draggable from 'vuedraggable'
// 列表数据
const list = ref([
{ id: 3, name: '张三' },
{ id: 4, name: '李四' },
{ id: 5, name: '王五' },
{ id: 6, name: '赵六' },
{ id: 7, name: '田七' },
])
</script>
<style lang="scss" scoped>
.list {
width: 500px;
border: 1px solid #000;
.item {
box-sizing: border-box;
width: 100%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
// 隔行变色
&:nth-child(even) {
background: #1fe63a;
}
&:nth-child(odd) {
background: rgb(207, 28, 58);
}
}
}
.data {
box-sizing: border-box;
padding: 20px;
width: 500px;
border: 1px solid #000;
font-family: serif;
}
</style>
3.使用插件vuedraggable@next实现两个列表之间相互拖拽
与第二点不同的是加个group属性,使用相同的name
vue3测试代码如下:
<template>
<div>
<!-- :group="{ name: 'task' }" 编组 -->
<div class="group">
<draggable class="list" v-model="list" item-key="id" :group="{ name: 'task' }">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
<draggable class="list" v-model="list2" item-key="id" :group="{ name: 'task' }">
<template #item="{ element }">
<div class="item">{{ element.name }}</div>
</template>
</draggable>
</div>
<div class="group">
<pre class="data">{{ list }}</pre>
<pre class="data">{{ list2 }}</pre>
</div>
</div>
</template>
<script setup >
import { ref } from 'vue'
import draggable from 'vuedraggable'
// 任务分配,需要对任务实现编组
// 列表数据
const list = ref([
{ id: 3, name: '开发任务A' },
{ id: 4, name: '开发任务B' },
{ id: 5, name: '开发任务C' },
{ id: 6, name: '开发任务D' },
{ id: 7, name: '开发任务E' },
])
const list2 = ref([
{ id: 11, name: '工作1' },
{ id: 12, name: '工作2' },
{ id: 13, name: '工作3' },
])
</script>
<style lang="scss" scoped>
.group {
display: flex;
}
.list {
width: 500px;
border: 1px solid #000;
margin: 30px;
.item {
box-sizing: border-box;
width: 100%;
height: 40px;
display: flex;
justify-content: center;
align-items: center;
// 隔行变色
&:nth-child(even) {
background: #1fe63a;
}
&:nth-child(odd) {
background: rgb(207, 28, 58);
}
}
}
.data {
box-sizing: border-box;
padding: 20px;
width: 500px;
border: 1px solid #000;
font-family: serif;
margin: 30px;
}
</style>
实现效果如下(开发任务与工作可以相互拖拽):
4.使用插件vuedraggable@next实现低代码拖拽效果
(1) 没有安装element-plus先安装npm i element-plus
(2) main.js再引入:
// main.js
import { createApp } from 'vue'
import App from './App.vue'
// 导入组件库
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
const app = createApp(App)
app.use(ElementPlus) // 使用组件库
app.mount('#app')
vue3测试代码如下:
<script setup >
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>
实现效果如下:
一些常见配置的详解:v-model与item-key必填,其他非必填
属性 | 说明 |
---|---|
v-model | 用于绑定拖动列表的数据。通常是一个数组,其中包含要显示和拖动的元素列表。必填 |
item-key | 每个元素唯一的标识,建议使用id。必填 |
group | 控制拖动元素的分组,可以传字符型、数组、对象。一般传对象比较灵活。 字符串:使用相同分组标识符的元素将属于同一分组,可以相互拖动。如<vuedraggable group="group1"> 数组:将多个分组标识符存储在数组中,从而使一个元素可以属于多个分组。如:<vuedraggable :group="['group1', 'group2']">"group1" 和 "group2" 分组,允许它与这两个分组中的元素互相拖动。 对象:传递包含更多配置信息的对象。对象可包含的属性。
|
disabled | 一个布尔值,用于禁用或启用拖动功能。 |
move | 一个回调函数,拖动时所做的事情。该函数接受两个参数:事件对象和元素。<vuedraggable v-model="myList" :move="handleMove"></vuedraggable> const handleMove = (event, element) => { console.log(event, element, '拖动') } |
start | 一个回调函数,开始拖动时所做的事情。 <vuedraggable v-model="myList" : @start="onDragStart"></vuedraggable> const onDragStart = (event) => { console.log(event, '开始') } |
end | 一个回调函数,结束拖动时所做的事情。 <vuedraggable v-model="myList" : @end="handleEnd"></vuedraggable> const handleEnd = (event) => { console.log(event, '结束') } |