最近幾天在研究有關vue實現拖拽的功能,不過跟通常的拖拽排序有點不一樣,這個需求可能出現多行多列嵌套的表單元素,數據也是遞歸形式的出現。我也是在vuedraggable的基礎上擴展實現的,如何想了解更多的拖拽排序功能能夠參考sortablejs.github.io/Vue.Draggab…javascript
Drag組件也是要遞歸的組件代碼css
<template>
<draggable
v-model="datas"
tag="v-layout"
class="row wrap fill-height align-center sortable-list"
style="background: grey;"
>
<v-flex
v-for="row in datas"
:key="row.index"
class="sorttable"
xs12
my-2
style="background: red"
>
<div class="row wrap justify-space-around">
<v-flex
v-for="item in row.items"
:key="item.id"
xs4
pa-3
class="row-v"
>
<!-- 加判斷若是item存在rows數組,則遞歸繼續執行這個組件-->
<template v-if="item.rows && Array.isArray(item.rows)">
<drag :data="item.rows" />
</template>
<draggable
v-else
:list="item.data"
tag="div"
:group="{ name: 'row'}"
:move="getData"
:animation="100"
:empty-insert-threshold="60"
@change="log"
>
<v-card
v-for="item2 in item.data"
:key="item2.title"
style="height: 100px;"
>
{{ item2.title }}
</v-card>
</draggable>
</v-flex>
</div>
</v-flex>
</draggable>
</template>
<script>
import draggable from 'vuedraggable'
import Vue from 'vue'
import Vuetify from 'vuetify'
import 'vuetify/dist/vuetify.min.css'
Vue.use(Vuetify)
export default {
name: 'Drag',
order: 17,
components: {
draggable
},
props: {
data: {
type: Array,
default () {
return []
}
}
},
data () {
return {
datas: this.data,
controlOnStart: true
}
},
methods: {
// 限制移動的方法
getData (e, d) {
if (e.relatedContext.list.length > 0) {
return false
}
},
log: function (evt) {
// window.console.log(evt)
// console.log(this.data)
if (Object.keys(evt)[0] === 'added') {
this.arrLoop(this.data, evt.added.element)
}
},
addHandler (e, d) {
// console.log(e)
},
endHandler (e, b) {
console.log(b)
},
// 遞歸實現遍歷數據
arrLoop (arr, ele) {
arr.forEach(item => {
const itemArr = item.data
if (itemArr && itemArr.length > 1) {
for (let i = 0; i < itemArr.length; i++) {
if (itemArr[i].title === ele.title) {
itemArr.splice(i, 1)
}
}
}
if (item.items && item.items.length) {
this.arrLoop(item.items, ele)
}
})
}
}
}
</script>
<style>
.buttons {
margin-top: 35px;
}
.row-v {
/* height: 150px;
width: 200px; */
width: 33%;
height: 100px;
display: inline-block;
background: blue;
border: 1px solid #ebebeb;
}
.row {
margin-left: 0;
margin-right: 0;
}
.ghost {
opacity: 0.5;
background: #c8ebfb;
}
</style>
複製代碼
注意:實現遞歸必定定義Drag組件的name值,要不就容易報錯vue
emptyInsertThreshold:拖動時,鼠標必須與空的可排序對象之間的距離(以像素爲單位),以便將拖動元素插入到該可排序對象中。默認爲5。設置爲0禁用此功能。這個參數要適當的設置,若是是默認值,當列爲空的時候,很難把元素拖進去,這個也是一個比較難解決的點,由於須要把右邊字段元素拖動到左邊空列中,或者左邊的元素移動到空的列裏。 move對應方法getData的方法主要實現若是relatedContext.list.length 大於0,則取消移動功能。 Drag的數據:rows: [
{
index: 1,
items: [
{
id: 1,
data: [{
title: 'item 1'
}]
},
{
id: 11,
data: [{
title: 'item 11'
}]
},
{
id: 12,
data: [
]
}
]
},
{
index: 2,
items: [
{
id: 0,
rows: [
{
index: 1,
items: [
{
id: 2,
data: [{
title: 'item 211'
}]
},
{
id: 3,
data: [{
title: 'item 212'
}]
}
]
},
{
index: 2,
items: [
{
id: 4,
data: [
{
title: 'item 222'
}
]
}
]
}
]
},
{
id: 5,
data: [{
title: 'item 3'
}]
}
]
},
{
index: 3,
items: [
{
id: 6,
data: [{
title: 'item 4'
}]
},
{
id: 7,
data: [{
title: 'item 5'
}]
},
{
id: 8,
data: []
}
]
}
]
複製代碼
右邊列表的組件代碼:java
<template>
<div>
<div
v-for="item in datas"
:key="item.id"
class="item-box"
>
<h2>{{ item.title }}</h2>
<div class="item-con">
<draggable
class="dragArea list-group"
:list="item.items"
:group="{ name: 'row', pull: 'clone', put: false }"
:clone="cloneDog"
>
<span
v-for="item2 in item.items"
:key="item2.id"
>
{{ item2.title }}
</span>
</draggable>
</div>
</div>
</div>
</template>
<script>
import draggable from 'vuedraggable'
export default {
name: 'Drag',
components: {
draggable
},
props: {
data: {
type: Array,
default () {
return []
}
}
},
data () {
return {
datas: [
{
id: 1,
title: '標題1',
items: [
{
id: 11,
title: 'item 11'
},
{
id: 12,
title: 'item 12'
}
]
},
{
id: 2,
title: '標題2',
items: [
{
id: 21,
title: 'item 21'
},
{
id: 22,
title: 'item 22'
}
]
}
]
}
},
methods: {
cloneDog (ele) {
// console.log(ele)
let b = this.arrLoop(this.rows, ele)
if (!b) {
return ele
}
},
arrLoop (arr, ele) {
for (let i = 0; i < arr.length; i++) {
if (arr[i].id === ele.id) {
return true
}
if (arr[i].items && arr[i].items.length) {
return this.arrLoop(arr[i].items, ele)
}
}
}
}
}
</script>
<style lang="scss" scoped>
.list-group{
span {
display: inline-block;
padding: 0 12px;
border-radius: 4px;
border: 1px solid #ebebeb;
line-height: 32px;
height: 32px;
background: #f5f5f5;
margin-right: 15px;
}
}
</style>
複製代碼
clone的cloneDog方法實現複製功能,首先遞歸循環數據判斷是須要複製的元素在左邊的列表中是否存在,如果存在,則取消複製,不存在,則複製。git
效果以下圖: github
這篇文章分享的主要技術點就是vuedraggable拖拽排序和複製、嵌套拖拽排序功能、vue組件遞歸功能,這僅表明我的觀點,想了解更多請掃描二維碼: 數組