当前位置:网站首页>如何玩转sortablejs-vuedraggable实现表单嵌套拖拽功能
如何玩转sortablejs-vuedraggable实现表单嵌套拖拽功能
2020-11-06 20:37:00 【叫我詹躲躲】
最近几天在研究有关vue实现拖拽的功能,不过跟一般的拖拽排序有点不同,这个需求可能出现多行多列嵌套的表单元素,数据也是递归形式的出现。我也是在vuedraggable的基础上扩展实现的,如何想了解更多的拖拽排序功能可以参考https://sortablejs.github.io/Vue.Draggable/#/simple
需要实现的功能
- 表单元素可能出现嵌套,数据出现树形结构
- 实现拖拽功能,表单元素可以移动到空的列里面,但是表单元素内容的不能来回拖拽排序
- 行与行之间可以拖动排序,列与列直接不能移动排序,能移动的只是字段数据也就是表单元素
- 右边列表里的字段可以拖拽添加到左边的空白没内容的列里面
用的技术点
- vue组件递归实现
- vuedraggable拖拽排序
- vuedraggable的例子Functional third party,主要是元素移动
- vuedraggable实现拖拽复制功能
- vuetify :vue ui组件,这里面主要用了它的删格系统和vcard卡片
实现功能的部分代码
Drag组件也是要递归的组件代码
<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值,要不就容易报错
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: []
}
]
}
]
右边列表的组件代码:
<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方法实现复制功能,首先递归循环数据判断是需要复制的元素在左边的列表中是否存在,若是存在,则取消复制,不存在,则复制。
效果如下图:
总结
这篇文章分享的主要技术点就是vuedraggable拖拽排序和复制、嵌套拖拽排序功能、vue组件递归功能。
版权声明
本文为[叫我詹躲躲]所创,转载请带上原文链接,感谢
https://my.oschina.net/u/3995971/blog/4558947
边栏推荐
猜你喜欢
CCR炒币机器人:“比特币”数字货币的大佬,你不得不了解的知识
怎么理解Python迭代器与生成器?
Python自动化测试学习哪些知识?
人工智能学什么课程?它将替代人类工作?
How long does it take you to work out an object-oriented programming interview question from Ali school?
数据产品不就是报表吗?大错特错!这分类里有大学问
(1)ASP.NET Core3.1 Ocelot介紹
This article will introduce you to jest unit test
DevOps是什么
合约交易系统开发|智能合约交易平台搭建
随机推荐
分布式ID生成服务,真的有必要搞一个
Real time data synchronization scheme based on Flink SQL CDC
Synchronous configuration from git to consult with git 2consul
Grouping operation aligned with specified datum
微服務 - 如何解決鏈路追蹤問題
Character string and memory operation function in C language
ES6 essence:
PN8162 20W PD快充芯片,PD快充充电器方案
速看!互联网、电商离线大数据分析最佳实践!(附网盘链接)
Cocos Creator 原始碼解讀:引擎啟動與主迴圈
基於MVC的RESTFul風格API實戰
你的财务报告该换个高级的套路了——财务分析驾驶舱
Technical director, to just graduated programmers a word - do a good job in small things, can achieve great things
【效能優化】納尼?記憶體又溢位了?!是時候總結一波了!!
(2)ASP.NET Core3.1 Ocelot路由
连肝三个通宵,JVM77道高频面试题详细分析,就这?
DevOps是什么
Cos start source code and creator
制造和新的自动化技术是什么?
Save the file directly to Google drive and download it back ten times faster