vuedraggable 介绍
vuedraggable 是基于Sortable.js 的 vue 组件库,没有 jQuery 依赖,可以实现视图和数据模型同步更新,并且拥有丰富的 API。
简单的例子
如果你需要使用上个实验的课程代码,请执行以下命令:
wget https://labfile.oss.aliyuncs.com/courses/1355/project1.zip
unzip project1.zip
cd project1
npm i
src/components/ 目录下新建 Draggable.vue
import Draggable from 'vuedraggable';
const message = [
'vue.draggable',
'draggable',
'component',
'for',
'vue.js 2.0',
'based',
'on',
'Sortablejs',
];
export default {
components: {
Draggable,
},
data() {
return {
list: message.map((name, index) => {
return { name, order: index + 1 };
}),
};
},
};
引用 vuedraggable 组件,定义一个数组来作为拖动元素的列表
<draggable
class="list-group"
tag="ul"
v-model="list"
v-bind="{
animation: 200,
group: 'description',
disabled: false,
ghostClass: 'ghost'
}"
>
<li class="list-group-item" v-for="element in list" :key="element.order">
{{ element.name }}
</li>
</draggable>
tag=”ul” 用来指定 draggable 组件渲染出来的 html 标签。
v-model 绑定列表可拖动元素,通常与内部元素 v-for 引用的数组相同。
v-bind 绑定组件的配置项,与 Sortable.js 的配置项相同,下面具体讲解:
group:string or object
string:命名,用处是为了设置可以拖放容器时使用
object: {name, pull, put}
name: 同 string 的方法
pull:pull 用来定义从这个列表容器移动出去的设置,true/false/‘clone’/function
true:列表容器内的列表元素可以被移出;
false:列表容器内的列表元素不可以被移出;
‘clone’:列表元素移出,移动的为该元素的副本;
function:用来进行 pull 的函数判断,可以进行复杂逻辑,在函数中 return false/true 来判断是否移出;
put:put 用来定义往这个列表容器放置列表元素的的设置,true/false/[‘foo’,’bar’]/function
true:列表容器可以从其他列表容器内放入列表元素;
false:与 true 相反;
[‘foo’,’bar’]:这个可以是一个字符串或者是字符串的数组,代表的是 group 配置项里定义的 name 值;
function:用来进行 put 的函数判断,可以进行复杂逻辑,在函数中 return false/true 来判断是否放入
animation: number 单位:ms,定义动画的时间;
disabled: boolean 定义此 sortable 对象是否可用,为 true 时 sortable 对象不能拖放排序等功能,为 false 时为可以进行排序,相当于一个开关;
ghostClass:selector 格式为简单 css 选择器的字符串,当拖动列表元素时会生成一个副本作为影子元素来模拟被拖动元素排序的情况,此配置项就是来给这个影子元素添加一个 class,我们可以通过这种方式来给影子元素进行编辑样式;
sort: boolean 定义是否列表元素是否可以在列表容器内进行拖拽排序;
delay: number 定义鼠标选中列表元素可以开始拖动的延迟时间;
handle: selector 格式为简单 css 选择器的字符串,使列表元素中符合选择器的元素成为拖动的手柄,只有按住拖动手柄才能使列表元素进行拖动;
filter: selector 格式为简单 css 选择器的字符串,定义哪些列表元素不能进行拖放,可设置为多个选择器,中间用“,”分隔
draggable:selector 格式为简单 css 选择器的字符串,定义哪些列表元素可以进行拖放
chosenClass:selector 格式为简单 css 选择器的字符串,当选中列表元素时会给该元素增加一个 class;
forceFallback:boolean 如果设置为 true 时,将不使用原生的 html5 的拖放,可以修改一些拖放中元素的样式等;
fallbackClass:string 当 forceFallback 设置为 true 时,拖放过程中鼠标附着元素的样式;
scroll:boolean 默认为 true,当排序的容器是个可滚动的区域,拖放可以引起区域滚动
<template>
<draggable
class="list-group"
tag="ul"
v-model="list"
v-bind="{
animation: 200,
group: 'description',
disabled: false,
ghostClass: 'ghost'
}"
>
<li class="list-group-item" v-for="element in list" :key="element.order">
{{ element.name }}
</li>
</draggable>
</template>
<script>
import Draggable from 'vuedraggable';
const message = [
'vue.draggable',
'draggable',
'component',
'for',
'vue.js 2.0',
'based',
'on',
'Sortablejs',
];
export default {
components: {
Draggable,
},
data() {
return {
list: message.map((name, index) => {
return { name, order: index + 1 };
}),
};
},
};
</script>
<style lang="scss">
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.list-group {
min-height: 20px;
list-style: none;
}
.list-group-item {
cursor: move;
height: 30px;
line-height: 30px;
border: 1px solid #ccc;
}
</style>
进阶的例子
<template>
<el-row :gutter="50">
<el-col :span="6">
<h3>Draggable 1</h3>
<draggable
class="list-group"
tag="ul"
v-model="list1"
v-bind="dragOptions"
>
<li class="list-group-item" v-for="element in list1" :key="element.id">
{{ element.name }}
</li>
</draggable>
</el-col>
<el-col :span="6">
<h3>Draggable 2</h3>
<draggable
class="list-group"
tag="ul"
v-model="list2"
v-bind="dragOptions"
>
<li class="list-group-item" v-for="element in list2" :key="element.id">
{{ element.name }}
</li>
</draggable>
</el-col>
<el-col :span="6">
<h3>List 1</h3>
<pre style="text-align: start;background: #f3f3f3;">
{{JSON.stringify(list1, null, 2)}}</pre
>
</el-col>
<el-col :span="6">
<h3>List 2</h3>
<pre style="text-align: start;background: #f3f3f3;">
{{JSON.stringify(list2, null, 2)}}</pre
>
</el-col>
</el-row>
</template>
<script>
import Draggable from 'vuedraggable';
export default {
components: {
Draggable,
},
data() {
return {
list1: [
{ name: 'Jesus', id: 1 },
{ name: 'Paul', id: 2 },
{ name: 'Peter', id: 3 },
],
list2: [
{ name: 'Luc', id: 5 },
{ name: 'Thomas', id: 6 },
{ name: 'John', id: 7 },
],
dragOptions: {
animation: 200,
group: 'people',
disabled: false,
ghostClass: 'ghost',
},
};
},
};
</script>
<style lang="scss">
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.list-group {
min-height: 20px;
list-style: none;
}
.list-group-item {
cursor: move;
height: 30px;
line-height: 30px;
border: 1px solid #ccc;
}
</style>
此处使用了 element-ui 的布局组件 el-row 来实现了页面的四列布局。
定义了 list1 、list2 两个数组,分别绑定到两个拖拽组件上面,并且设置配置项 dragOptions: {group: 'people'}
,实现元素可以在两个拖拽组件中拖动。
可以看到在拖动过程中,定义的数组会随着拖动元素的改变而改变。
现在是否看上去有点表单元素拖拽的感觉了,接下来我们让左边元素保持不变,拖拽到右边的时候自动添加一项,修改第一个拖拽组件的配置项,让其数组不会随着拖动而改变
<template>
<el-row :gutter="50">
<el-col :span="6">
<h3>Draggable 1</h3>
<draggable
class="list-group"
tag="ul"
v-model="list1"
v-bind="dragOptions1"
>
<li class="list-group-item" v-for="element in list1" :key="element.id">
{{ element.name }}
</li>
</draggable>
</el-col>
<el-col :span="6">
<h3>Draggable 2</h3>
<draggable
class="list-group"
tag="ul"
v-model="list2"
v-bind="dragOptions2"
>
<li class="list-group-item" v-for="element in list2" :key="element.id">
{{ element.name }}
</li>
</draggable>
</el-col>
...
</el-row>
</template>
<script>
import Draggable from 'vuedraggable';
export default {
components: {
Draggable,
},
data() {
return {
// ...
dragOptions1: {
animation: 200,
group: { name: 'people', pull: 'clone', put: false }, // 配置项
disabled: false,
ghostClass: 'ghost',
},
dragOptions2: {
animation: 200,
group: 'people',
disabled: false,
ghostClass: 'ghost',
},
};
},
};
</script>
修改配置项 group,使元素移出的是元素的副本并且不允许其他列表的元素移入进来
拖拽事件
拖拽组件提供了如下事件:
- onChoose:列表元素被选中的回调函数
- onStart:列表元素拖动开始的回调函数
- onEnd:列表元素拖放结束后的回调函数
- onAdd:列表元素添加到本列表容器的回调函数
- onUpdate:列表元素在列表容器中的排序发生变化后的回调函数
- onRemove:列表元素移到另一个列表容器的回调函数
- onFilter:试图选中一个被 filter 过滤的列表元素的回调函数
- onMove:当移动列表元素在一个列表容器中或者多个列表容器中的回调函数
- onClone:当创建一个列表元素副本的时候的回调函数
事件对象:
(事件对象在各个函数中略有不同,可通过输出对象查看对象的属性,下面简单列举几个:)
- to:HTMLElement—移动到列表容器
- from:HTMLElement—来源的列表容器
- item:HTMLElement—被移动的列表元素
- clone:HTMLElement—副本的列表元素
- oldIndex:number/undefined—在列表容器中的原序号
- newIndex:number/undefined—在列表容器中的新序号
<draggable
class="list-group"
tag="ul"
v-model="list2"
v-bind="dragOptions2"
@add="onAdd"
>
...
</draggable>
// 添加 onAdd 方法
export default {
//...
methods: {
onAdd(evt) {
alert(evt.oldIndex + '->' + evt.newIndex);
},
},
};