加载中...

前端拖拽-vuedraggable的使用

前端拖拽-vuedraggable的使用

本文将对vuedraggable官方的示例增加说明,帮助友友们更快的实现拖拽的效果

官网例子: sortablejs.github.io/Vue.Draggab…

1. 拖拽后,数据能够更新

New Image

如上图,我们把Joao拖拽和Jean交换,希望数据List能够发生改变

js
代码解读
复制代码
import draggable from ''vuedraggable'' // 如果没有这个包的,自行npm下载vuedraggable export default { name: ''dragable'', components: { draggable // 注册组件 },

如上代码,先引入包,再注册组件

html
代码解读
复制代码
<draggable :list="list" > <div class="list-group-item" v-for="element in list" :key="element.name" > {{ element.name }} </div> </draggable>

如上,使用draggable组件包裹要拖拽的列表,增加list属性,传入列表数据list,这样后,数据就能够在拖拽同时发生更新。

New Image 上图为修改后的效果

2. 两个list之间的拖拽

vuedraggable能够支持两个列表之间进行拖拽 New Image 如上图,想把Joao拖拽到Edgard下面去

diff
代码解读
复制代码
<div > + <draggable :list="list1" + group="people" > <div v-for="element in list1" :key="element.name" > {{ element.name }} </div> </draggable> </div> <div > + <draggable :list="list2" + group="people" > <div v-for="element in list2" :key="element.name" > {{ element.name }} </div> </draggable> </div>
js
代码解读
复制代码

如上代码,增加group属性其值为people,两个list的group属性值必须一致拖拽才会生效

New Image 效果如上,能够拖拽成功

3. 拖拽复制

希望拖拽后是复制而不是移除的效果 New Image

diff
代码解读
复制代码
<div > <draggable :list="list1" + :group="{name: ''people'', pull: ''clone'', put: false}" > <div v-for="element in list1" :key="element.name" > {{ element.name }} </div> </draggable> </div> <div > <draggable :list="list2" group="people" > <div 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属性

具体参考选项New Image

注意复制时,id可能会发生重复 New Image 解决方案:

diff
代码解读
复制代码
<div > <!-- 拖拽复制 --> <div > <draggable :list="list" + :clone="clone" :group="{name: ''people'', pull: ''clone'', put: false}" > <div v-for="element in list" :key="element.name" > {{ element.name }} </div> </draggable>

在methods中增加方法

js
代码解读
复制代码
methods: { clone ({ name }) { // 复制过去的数据项,是list2长度+1 return { name, id: this.list2.length } } }

4. 按住ctrl进行复制

希望按住ctrl拖动就是复制;没按ctrl键进行拖拽就是移动

diff
代码解读
复制代码
<draggable :list="list1" + :group="{name: ''people'', pull: pullFunction}" @start="start" > <div v-for="element in list1" :key="element.name" > {{ element.name }} </div> </draggable>
js
代码解读
复制代码
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键

New Image

New Image

如上两幅图,能够复制成功,但是当复制多个时,发现报错,原因是id重复了,所以我们还应该添加如下:

diff
代码解读
复制代码
<draggable :list="list1" :group="{name: ''people'', pull: pullFunction}" + :clone="clone" @start="start" > <div v-for="element in list1" :key="element.name" > {{ element.name }} </div> </draggable>
diff
代码解读
复制代码
<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. 点击拖拽按钮,才可以进行拖动

希望点击图标才可以进行拖拽 New Image

diff
代码解读
复制代码
<draggable :list="list" + handle=".handle" :group="{name: ''people'', pull: pullFunction, put: false}" tag="ul" > <li v-for="element in list" :key="element.name" > <!-- 该图标添加handle类 --> + <i ></i> <span> {{ element.name }}</span> <input type="text" v-model="element.text" /> </li> </draggable>

对应css代码

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值任取,需要和下面的标签类名对应
diff
代码解读
复制代码
<draggable :list="list" :group="{name: ''people'', pull: true, put: false}" tag="ul" v-bind="dragOptions" > + <transition-group + type="transition" + name="flip-list" > <li v-for="element in list" :key="element.name" > <span> {{ element.name }}</span> </li> </transition-group> </draggable>

增加样式,如下类名需要和transition-group里面的name进行对应

css
代码解读
复制代码
.flip-list-move { transition: transform 0.5s; }

把dragOptions的animation改为200,是另一种过渡效果,详见官网实例

diff
代码解读
复制代码
computed: { dragOptions() { return { + animation: 200, group: ''description'', disabled: false, ghostClass: "ghost" } } },

animation属性控制动画的速度,设置为200后更加丝滑一些~,如下描述:

New Image

7. 表格拖拽移动行

希望在表格的行与行之间进行拖拽。如下图,把id为1的数据拖拽和id为2的数据进行交换;通过控制台看到list2数据也发生了改变 New Image

表格拖拽移动时:

调整结构

diff
代码解读
复制代码
<div > <!-- 拖拽有transition过渡效果 --> <div > + <table > <thead > <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>

数据调整

js
代码解读
复制代码
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" } ], } },

样式调整

css
代码解读
复制代码
<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数据不更新
diff
代码解读
复制代码
<template> <div > <!-- 表格拖拽移动列 --> <div > <table > + <thead > + <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>
diff
代码解读
复制代码
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. 嵌套数据的拖拽

希望嵌套的数据支持拖拽,页面效果如下:

New Image

拖拽后,数据也发生了改变

New Image

列表数据

js
代码解读
复制代码
list: [ { name: "task 1", tasks: [ { name: "task 2", tasks: [] } ] }, { name: "task 3", tasks: [ { name: "task 4", tasks: [] } ] }, { name: "task 5", tasks: [] } ]

组件注册

vue
代码解读
复制代码
<template> <div > <nestedDraggable :tasks="list"></nestedDraggable> </div> </template> <script> import nestedDraggable from ''@/components/nested-draggable.vue'' export default { name: ''Layout'', components: { nestedDraggable },

在nested-draggable.vue组件中

diff
代码解读
复制代码
<template> <div > <!-- 嵌套列表拖拽 --> <draggable :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

js
代码解读
复制代码
props: { tasks: { type: Array, required: true } },