需要先了解:
Sortable.js插件的配置信息
vue.draggable的clone拷贝实现常用菜单功能
本文参考文章 记录一下vuedraggable clone的坑,获取数据
前排提示: 如果你也遇到了编辑拖拽的单元数据时,原单元数据也跟着发生了变化,可以直接拖到最后看解决方法。
要实现的效果
有两个列表:
列表A为预设的组件,不能添加编辑和删除;
列表B为编辑区域,需要从列表A中拖拽组件,然后修改组件名称等一些信息。
通过分析需求,我们可以知道:
- 列表A和B的group name需相同;
- 列表A需要设置:
- 移动单元时,移动的为该单元副本
- 不可向列表内拖拽组件
- 列表页单元不能排序
由此可以得出列表A:
<draggable v-model="defaultFields" :sort="false" :group="{name:'piece',pull:'clone',put:false}">
<div v-for="item in defaultFields">
<span class="icon"><i :class="item.icon"></i></span>
<span class="name">{{item.name}}</span>
</div>
</draggable>
列表B:
<draggable
v-model="fields"
:group="{name:'piece'}"
animation="200"
@add="addFlowField"
>
<div v-for='(item, index) in tableFlow[thisFlow.index].fields' @click='setFieldData(index)'>
<!-- 中间代码省略(通过判断item.type来渲染不同的页面样式) -->
</div>
</draggable>
列表A与B中的数据结构:(两个数组之间的数据结构均大致相同,仅对页面渲染产生影响,并不会影响到拖拽后列表单元的数据)
[
{
name:'单行文本',
description:'',
type:'string',
default_value:'',
form_not_null:0,
is_search:0,
// 是否允许使用相册
is_album:0,
// 图标
icon: 'fa fa-pencil-square-o'
},
{
name:'多行文本',
description:'',
type:'textarea',
default_value:'',
form_not_null:0,
is_search:0,
// 是否允许使用相册
is_album:0,
// 图标
icon: 'fa fa-file-text-o'
},
// ...省略部分数据
]
当从列表A拖拽单元到列表B时,可以达到我们的要求:
但是当我们需要修改拖拽得到的单元信息时(比如名称),列表A中对应的单元也发生了变化:
这是因为在拖拽时,vue.draggable只是从列表A复制了对应位置的数据,然后插入到列表B,这个数据的指针(?)并没有发生变化,都是指向列表A中的单元,所以在修改时,就相当于修改了列表A中的单元数据。
解决方法
在复制列表A中的单元时,深拷贝一份数据到列表B,而不是直接复制。
在列表A中添加 :clone 事件,对拖拽的数据进行二手加工:(注意不是 @clone )
<draggable v-model="defaultFields" :sort="false" :group="{name:'piece',pull:'clone',put:false}" :clone="cloneDefaultField">
<div v-for="item in defaultFields">
<span class="icon"><i :class="item.icon"></i></span>
<span class="name">{{item.name}}</span>
</div>
</draggable>
cloneDefaultField(e){
return JSON.parse(JSON.stringify(e));
}