本文将对vuedraggable官方的示例增加说明,帮助友友们更快的实现拖拽的效果
1. 拖拽后,数据能够更新
如上图,我们把Joao拖拽和Jean交换,希望数据List能够发生改变
import draggable from 'vuedraggable' // 如果没有这个包的,自行npm下载vuedraggable
export default {
name: 'dragable',
components: {
draggable // 注册组件
},
如上代码,先引入包,再注册组件
<draggable
:list="list"
>
<div
class="list-group-item"
v-for="element in list"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
如上,使用draggable组件包裹要拖拽的列表,增加list属性,传入列表数据list,这样后,数据就能够在拖拽同时发生更新。
上图为修改后的效果
2. 两个list之间的拖拽
vuedraggable能够支持两个列表之间进行拖拽
如上图,想把Joao拖拽到Edgard下面去
<div class="list-group">
+ <draggable
:list="list1"
+ group="people"
>
<div
class="list-group-item"
v-for="element in list1"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
</div>
<div class="list-group">
+ <draggable
:list="list2"
+ group="people"
>
<div
class="list-group-item"
v-for="element in list2"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
</div>
如上代码,增加group属性其值为people,两个list的group属性值必须一致拖拽才会生效
效果如上,能够拖拽成功
3. 拖拽复制
希望拖拽后是复制而不是移除的效果
<div class="list-group">
<draggable
:list="list1"
+ :group="{name: 'people', pull: 'clone', put: false}"
>
<div
class="list-group-item"
v-for="element in list1"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
</div>
<div class="list-group">
<draggable
:list="list2"
group="people"
>
<div
class="list-group-item"
v-for="element in list2"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
</div>
如上代码,需要把group属性,修改为一个对象,其中:
- name值依然是'people',
- pull值若为clone,意味着左侧列表拖动到其他列表是复制,若值为false表示不能拖走,为true表示能移走;
- put改为false,表示左侧列表别人无法拖动插入进来,true表示可以;put没有没有clone属性
注意复制时,id可能会发生重复
解决方案:
<div class="box">
<!-- 拖拽复制 -->
<div class="list-group">
<draggable
:list="list"
+ :clone="clone"
:group="{name: 'people', pull: 'clone', put: false}"
>
<div
class="list-group-item"
v-for="element in list"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
在methods中增加方法
methods: {
clone ({ name }) {
// 复制过去的数据项,是list2长度+1
return { name, id: this.list2.length }
}
}
4. 按住ctrl进行复制
希望按住ctrl拖动就是复制;没按ctrl键进行拖拽就是移动
<draggable
:list="list1"
+ :group="{name: 'people', pull: pullFunction}"
@start="start"
>
<div
class="list-group-item"
v-for="element in list1"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
pullFunction () {
return this.onControlStart ? 'clone': true
},
start ({ originalEvent }) {
this.onControlStart = originalEvent.ctrlKey
}
如上代码中,group对象的pull使用自定义函数,pullFunction方法判断onControlStart变量,如果为true则开启复制,否则是移动;在draggable组件上绑定start事件,拖拽开始触发,在start方法里面修改onControlStart变量的值,originalEvent变量的ctrlKey为true表示按了ctrl键
如上两幅图,能够复制成功,但是当复制多个时,发现报错,原因是id重复了,所以我们还应该添加如下:
<draggable
:list="list1"
:group="{name: 'people', pull: pullFunction}"
+ :clone="clone"
@start="start"
>
<div
class="list-group-item"
v-for="element in list1"
:key="element.name"
>
{{ element.name }}
</div>
</draggable>
<script>
import draggable from 'vuedraggable'
+let idGlobal = 8
export default {
name: 'dragable',
components: {
draggable
},
data () {
return {
list1: [
{ name: "John", id: 0 },
{ name: "Joao", id: 1 },
{ name: "Jean", id: 2 }
],
list2: [
{ name: "Juan", id: 5 },
{ name: "Edgard", id: 6 },
{ name: "Johnson", id: 7 }
],
onControlStart: true, // 是否复制
}
},
props: {
},
watch: {
},
created () {
},
mounted () { },
methods: {
+ clone ({ name }) {
return { name, id: idGlobal++} // 每次复制的时候,id应该++
},
pullFunction () {
return this.onControlStart ? 'clone': true
},
start ({ originalEvent }) {
this.onControlStart = originalEvent.ctrlKey
}
}
}
</script>
5. 点击拖拽按钮,才可以进行拖动
希望点击图标才可以进行拖拽
<draggable
:list="list"
+ handle=".handle"
:group="{name: 'people', pull: pullFunction, put: false}"
tag="ul"
>
<li
class="list-group-item"
v-for="element in list"
:key="element.name"
>
<!-- 该图标添加handle类 -->
+ <i class="el-icon-rank handle"></i>
<span> {{ element.name }}</span>
<input type="text" class="form-control" v-model="element.text" />
</li>
</draggable>
对应css代码
.box {
display: flex;
width: 300px;
}
.list-group:first-child {
margin-right: 20px;
}
.list-group-item {
position: relative;
display: flex;
justify-content: space-between;
align-items: center;
padding: .75rem 1.25rem;
margin-bottom: -1px;
background-color: #fff;
border: 1px solid rgba(0, 0, 0, .125);
span {
margin-left: 20px;
}
input {
margin-left: 20px;
}
}
6 过渡效果
希望拖拽移动能有过渡效果:示例效果
- 添加transition-group标签
- type改为transition
- name值任取,需要和下面的标签类名对应
<draggable
:list="list"
:group="{name: 'people', pull: true, put: false}"
tag="ul"
v-bind="dragOptions"
>
+ <transition-group
+ type="transition"
+ name="flip-list"
>
<li
class="list-group-i tem"
v-for="element in list"
:key="element.name"
>
<span> {{ element.name }}</span>
</li>
</transition-group>
</draggable>
增加样式,如下类名需要和transition-group里面的name进行对应
.flip-list-move {
transition: transform 0.5s;
}
把dragOptions的animation改为200,是另一种过渡效果,详见官网实例
computed: {
dragOptions() {
return {
+ animation: 200,
group: 'description',
disabled: false,
ghostClass: "ghost"
}
}
},
animation属性控制动画的速度,设置为200后更加丝滑一些~,如下描述:
7. 表格拖拽移动行
希望在表格的行与行之间进行拖拽。如下图,把id为1的数据拖拽和id为2的数据进行交换;通过控制台看到list2数据也发生了改变
表格拖拽移动时:
调整结构
<div class="box">
<!-- 拖拽有transition过渡效果 -->
<div class="list-group">
+ <table class="table table-striped">
<thead class="thead-dark">
<tr>
<th scope="col" width="100">Id</th>
<th scope="col" width="200">Name</th>
<th scope="col" width="100">Sport</th>
</tr>
</thead>
<draggable
:list="list"
:group="{name: 'people', pull: true, put: false}"
+ tag="tbody"
v-bind="dragOptions"
>
+ <tr v-for="item in list" :key="item.id">
<td scope="row">{{ item.id }}</td>
<td>{{ item.name }}</td>
<td>{{ item.sport }}</td>
</tr>
</draggable>
</table>
</div>
</div>
数据调整
data () {
return {
list: [
{ id: 1, name: "Abby", sport: "basket" },
{ id: 2, name: "Brooke", sport: "foot" },
{ id: 3, name: "Courtenay", sport: "volley" },
{ id: 4, name: "David", sport: "rugby" }
],
}
},
样式调整
<style scoped lang='less'>
.table .thead-dark {
color: #fff;
background-color: #343a40;
border-color: #454d55;
}
</style>
8. 表格拖拽移动列
希望拖拽表格的列。和拖拽行的不同点:
- draggable包裹的是thead里面的th标签,一个th就是一个表头,注意不要包裹整个thead了
- draggable不要忘记绑定v-model="headers", tag="tr"
- tbody里面的tr用v-for遍历list值,td用v-for遍历headers值,最终渲染的值是item[header],不能像原来那样只v-for遍历list,否则拖拽列后下面的td数据不更新
<template>
<div class="box">
<!-- 表格拖拽移动列 -->
<div class="list-group">
<table class="table table-striped">
+ <thead class="thead-dark">
+ <draggable v-model="headers" tag="tr">
+ <th v-for="header in headers" :key="header" width="100" scope="col">{{ header }}</th>
+ </draggable>
+ </thead>
<tbody>
+ <tr v-for="item in list" :key="item.id">
+ <td v-for="header in headers" :key="header" width="100">{{ item[header] }}</td>
+ </tr>
</tbody>
</table>
</div>
</div>
</template>
data () {
return {
+ headers: ["id", "name", "sport"],
list: [
{ id: 1, name: "Abby", sport: "basket" },
{ id: 2, name: "Brooke", sport: "foot" },
{ id: 3, name: "Courtenay", sport: "volley" },
{ id: 4, name: "David", sport: "rugby" }
],
}
},
9. 嵌套数据的拖拽
希望嵌套的数据支持拖拽,页面效果如下:
拖拽后,数据也发生了改变
列表数据
list: [
{
name: "task 1",
tasks: [
{
name: "task 2",
tasks: []
}
]
},
{
name: "task 3",
tasks: [
{
name: "task 4",
tasks: []
}
]
},
{
name: "task 5",
tasks: []
}
]
组件注册
<template>
<div class="Layout">
<nestedDraggable :tasks="list"></nestedDraggable>
</div>
</template>
<script>
import nestedDraggable from '@/components/nested-draggable.vue'
export default {
name: 'Layout',
components: {
nestedDraggable
},
在nested-draggable.vue组件中
<template>
<div class="box">
<!-- 嵌套列表拖拽 -->
<draggable
class="dragArea"
:list="tasks"
tag="ul"
:group="{name: 'g1'}"
>
<li
v-for="el in tasks"
:key="el.name"
>
<p>{{ el.name }}</p>
+ 在这里进行嵌套,关键!
+ <nested-draggable :tasks="el.tasks"></nested-draggable>
</li>
</draggable>
</div>
</template>
必须接受props
props: {
tasks: {
type: Array,
required: true
}
},