本文将对vuedraggable官方的示例增加说明,帮助友友们更快的实现拖拽的效果
官网例子: sortablejs.github.io/Vue.Draggab…
1. 拖拽后,数据能够更新
如上图,我们把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,这样后,数据就能够在拖拽同时发生更新。
上图为修改后的效果
2. 两个list之间的拖拽
vuedraggable能够支持两个列表之间进行拖拽
如上图,想把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属性值必须一致拖拽才会生效
效果如上,能够拖拽成功
3. 拖拽复制
希望拖拽后是复制而不是移除的效果
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属性
注意复制时,id可能会发生重复
解决方案:
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键
如上两幅图,能够复制成功,但是当复制多个时,发现报错,原因是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. 点击拖拽按钮,才可以进行拖动
希望点击图标才可以进行拖拽
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后更加丝滑一些~,如下描述:
7. 表格拖拽移动行
希望在表格的行与行之间进行拖拽。如下图,把id为1的数据拖拽和id为2的数据进行交换;通过控制台看到list2数据也发生了改变
表格拖拽移动时:
调整结构
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. 嵌套数据的拖拽
希望嵌套的数据支持拖拽,页面效果如下:
拖拽后,数据也发生了改变
列表数据
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 } },