Draggable為基于Sortable.js的vue組件,用以實(shí)現(xiàn)拖拽功能。
特性
支持觸摸設(shè)備
支持拖拽和選擇文本
支持智能滾動(dòng)
支持不同列表之間的拖拽
不以jQuery為基礎(chǔ)
和視圖模型同步刷新
和vue2的國(guó)度動(dòng)畫兼容
支持撤銷操作
當(dāng)需要完全控制時(shí),可以拋出所有變化
可以和現(xiàn)有的UI組件兼容
安裝
npm install vuedraggable
引入
import draggable from 'vuedraggable'
官方例子:
hello.vue
<template>
<div class="fluid container">
<div class="form-group form-group-lg panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Sortable control</h3>
</div>
<div class="panel-body">
<div class="checkbox">
<label><input type="checkbox" v-model="editable">Enable drag and drop</label>
</div>
<button type="button" class="btn btn-default" @click="orderList">Sort by original order</button>
</div>
</div>
<div class="col-md-3">
<draggable class="list-group" element="ul" v-model="list" :options="dragOptions" :move="onMove" @start="isDragging=true" @end="isDragging=false">
<transition-group type="transition" :name="'flip-list'">
<li class="list-group-item" v-for="element in list" :key="element.order">
<i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
{{element.name}}
<span class="badge">{{element.order}}</span>
</li>
</transition-group>
</draggable>
</div>
<div class="col-md-3">
<draggable element="span" v-model="list2" :options="dragOptions" :move="onMove">
<transition-group name="no" class="list-group" tag="ul">
<li class="list-group-item" v-for="element in list2" :key="element.order">
<i :class="element.fixed? 'fa fa-anchor' : 'glyphicon glyphicon-pushpin'" @click=" element.fixed=! element.fixed" aria-hidden="true"></i>
{{element.name}}
<span class="badge">{{element.order}}</span>
</li>
</transition-group>
</draggable>
</div>
<div class="list-group col-md-3">
<pre>{{listString}}</pre>
</div>
<div class="list-group col-md-3">
<pre>{{list2String}}</pre>
</div>
</div>
</template>
<script>
import draggable from "vuedraggable";
const message = [
"vue.draggable",
"draggable",
"component",
"for",
"vue.js 2.0",
"based",
"on",
"Sortablejs"
];
export default {
name: "hello",
components: {
draggable
},
data() {
return {
list: message.map((name, index) => {
return { name, order: index + 1, fixed: false };
}),
list2: [],
editable: true,
isDragging: false,
delayedDragging: false
};
},
methods: {
orderList() {
this.list = this.list.sort((one, two) => {
return one.order - two.order;
});
},
onMove({ relatedContext, draggedContext }) {
const relatedElement = relatedContext.element;
const draggedElement = draggedContext.element;
return (
(!relatedElement || !relatedElement.fixed) && !draggedElement.fixed
);
}
},
computed: {
dragOptions() {
return {
animation: 0,
group: "description",
disabled: !this.editable,
ghostClass: "ghost"
};
},
listString() {
return JSON.stringify(this.list, null, 2);
},
list2String() {
return JSON.stringify(this.list2, null, 2);
}
},
watch: {
isDragging(newValue) {
if (newValue) {
this.delayedDragging = true;
return;
}
this.$nextTick(() => {
this.delayedDragging = false;
});
}
}
};
</script>
<style>
.flip-list-move {
transition: transform 0.5s;
}
.no-move {
transition: transform 0s;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
.list-group {
min-height: 20px;
}
.list-group-item {
cursor: move;
}
.list-group-item i {
cursor: pointer;
}
</style>
main.js
import Vue from "vue";
import App from "./App.vue";
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/less/font-awesome.less";
Vue.config.productionTip = false;
new Vue({
render: h => h(App)
}).$mount("#app");
屬性和方法說(shuō)明
屬性
value
Array,非必須,默認(rèn)為null
用于實(shí)現(xiàn)拖拽的list,通常和內(nèi)部v-for循環(huán)的數(shù)組為同一數(shù)組。
最好使用vuex來(lái)實(shí)現(xiàn)傳入。
不是直接使用,而是通過(guò)v-model引入。
<draggable v-model="myArray">
list
Array,非必須,默認(rèn)為null
就是value的替代品。
和v-model不能共用
從表現(xiàn)上沒有看出不同
element
String,默認(rèn)div
就是<draggable>標(biāo)簽在渲染后展現(xiàn)出來(lái)的標(biāo)簽類型
也是包含拖動(dòng)列表和插槽的外部標(biāo)簽
可以用來(lái)兼容UI組件
options
Object
配置項(xiàng)
group: string or array 分組用的,同一組的不同list可以相互拖動(dòng)
sort: boolean 定義是否可以拖拽
delay:number 定義鼠標(biāo)選中列表單元可以開始拖動(dòng)的延遲時(shí)間
touchStartThreshold:number (不清楚)
disabled: boolean 定義是否此sortable對(duì)象是否可用,為true時(shí)sortable對(duì)象不能拖放排序等功能
store:
animation: umber 單位:ms 動(dòng)畫時(shí)間
handle: selector 格式為簡(jiǎn)單css選擇器的字符串,使列表單元中符合選擇器的元素成為拖動(dòng)的手柄,只有按住拖動(dòng)手柄才能使列表單元進(jìn)行拖動(dòng)
filter: selector 格式為簡(jiǎn)單css選擇器的字符串,定義哪些列表單元不能進(jìn)行拖放,可設(shè)置為多個(gè)選擇器,中間用“,”分隔
preventOnFilter: 當(dāng)拖動(dòng)filter時(shí)是否觸發(fā)event.preventDefault()默認(rèn)觸發(fā)
draggable: selector 格式為簡(jiǎn)單css選擇器的字符串,定義哪些列表單元可以進(jìn)行拖放
ghostClass: selector 格式為簡(jiǎn)單css選擇器的字符串,當(dāng)拖動(dòng)列表單元時(shí)會(huì)生成一個(gè)副本作為影子單元來(lái)模擬被拖動(dòng)單元排序的情況,此配置項(xiàng)就是來(lái)給這個(gè)影子單元添加一個(gè)class,我們可以通過(guò)這種方式來(lái)給影子元素進(jìn)行編輯樣式
chosenClass: selector 格式為簡(jiǎn)單css選擇器的字符串,目標(biāo)被選中時(shí)添加
dragClass:selector 格式為簡(jiǎn)單css選擇器的字符串,目標(biāo)拖動(dòng)過(guò)程中添加
forceFallback: boolean 如果設(shè)置為true時(shí),將不使用原生的html5的拖放,可以修改一些拖放中元素的樣式等
fallbackClass: string 當(dāng)forceFallback設(shè)置為true時(shí),拖放過(guò)程中鼠標(biāo)附著單元的樣式
dataIdAttr: data-id
scroll:boolean當(dāng)排序的容器是個(gè)可滾動(dòng)的區(qū)域,拖放可以引起區(qū)域滾動(dòng)
scrollFn:function(offsetX, offsetY, originalEvent, touchEvt, hoverTargetEl) { … } 用于自定義滾動(dòng)條的適配
scrollSensitivity: number 就是鼠標(biāo)靠近邊緣多遠(yuǎn)開始滾動(dòng)默認(rèn)30
scrollSpeed: number 滾動(dòng)速度
函數(shù)配置
setData: 設(shè)置值時(shí)的回調(diào)函數(shù)
onChoose: 選擇單元時(shí)的回調(diào)函數(shù)
onStart: 開始拖動(dòng)時(shí)的回調(diào)函數(shù)
onEnd: 拖動(dòng)結(jié)束時(shí)的回調(diào)函數(shù)
onAdd: 添加單元時(shí)的回調(diào)函數(shù)
onUpdate: 排序發(fā)生變化時(shí)的回調(diào)函數(shù)
onRemove: 單元被移動(dòng)到另一個(gè)列表時(shí)的回調(diào)函數(shù)
onFilter: 嘗試選擇一個(gè)被filter過(guò)濾的單元的回調(diào)函數(shù)
onMove: 移動(dòng)單元時(shí)的回調(diào)函數(shù)
onClone: clone時(shí)的回調(diào)函數(shù)
以上函數(shù)對(duì)象的屬性:
to: 移動(dòng)到的列表的容器
from:來(lái)源列表容器
item: 被移動(dòng)的單元
clone: 副本的單元
oldIndex:移動(dòng)前的序號(hào)
newIndex:移動(dòng)后的序號(hào)
clone
function,默認(rèn)值: 無(wú)處理
這一項(xiàng)要配合著options的group項(xiàng)的pull項(xiàng)處理,當(dāng)pull:'clone時(shí)的拖拽的回調(diào)函數(shù)’
就是克隆的意思。
可以理解為正常的拖拽變成了復(fù)制。
當(dāng)為true時(shí)克隆
move
function,默認(rèn)值:null
就是拖拽項(xiàng)時(shí)調(diào)用的函數(shù)
用來(lái)確定拖拽是否生效
返回null時(shí)可以生效
可以通過(guò)函數(shù)判斷
有一個(gè)參數(shù):evt
evt為object
draggedContext: 被拖拽元素的上下文
index:拖拽元素的指針
element: 拖拽數(shù)據(jù)本身
futureIndex: 拖動(dòng)后的index
relatedContext: 拖入?yún)^(qū)域的上下文
index: 目標(biāo)元素的index
element:目標(biāo)數(shù)據(jù)本身
list: 拖入的列表
component:目標(biāo)組件
<draggable element="ul" v-model="list" :move='allow'>
...
methods: {
allow(evt) {
console.log(evt.draggedContext.index)
console.log(evt.draggedContext.element)
console.log(evt.draggedContext.futureIndex)
console.log(evt.relatedContext.index)
console.log(evt.relatedContext.element)
console.log(evt.relatedContext.list)
console.log(evt.relatedContext.component)
return (evt.draggedContext.element.name!== 'b')
}
}
componentData
Object,默認(rèn)值:null
用來(lái)結(jié)合UI組件的,可以理解為代理了UI組件的定制信息
包含兩項(xiàng):props和on
props用來(lái)代理UI組件需要綁定的屬性(:)
on用來(lái)代理UI組件需要綁定的事件(@)
<draggable element="el-collapse" :list="list" :component-data="getComponentData()">
<el-collapse-item v-for="e in list" :title="e.title" :name="e.name" :key="e.name">
<div>{{e.description}}</div>
</el-collapse-item>
</draggable>
methods: {
handleChange() {
console.log('changed');
},
inputChanged(value) {
this.activeNames = value;
},
getComponentData() {
return {
on: {
change: this.handleChange,
input: this.inputChanged
},
props: {
value: this.activeNames
}
};
}
}
事件
有以下幾種
start, add, remove, update, end, choose, sort, filter, clone
參數(shù)帶有如下屬性:
add: 包含被添加到列表的元素
newIndex: 添加后的新索引
element: 被添加的元素
removed: 從列表中移除的元素
oldIndex: 移除前的索引
element: 被移除的元素
moved:內(nèi)部移動(dòng)的
newIndex: 改變后的索引
oldIndex: 改變前的索引
element: 被移動(dòng)的元素
插槽
提供一個(gè)footer插槽,在排序列表之下。
永遠(yuǎn)位于最下方。
<draggable v-model="myArray" :options="{draggable:'.item'}">
<div v-for="element in myArray" :key="element.id" class="item">
{{element.name}}
</div>
<button slot="footer" @click="addPeople">Add</button>
</draggable>
