功能描述:
1、左边【一级、二级、三级】字样是不能拖拽的,【item1、item2...】可以拖拽
2、左边items位置固定,只能向右拖拽,不能上下拖拽,如:item7从左边拖到右边,左边的item7消失,右边增加item7
3、右边items可以自由拖拽,但不能向左拖拽
4、右边items可以删除,如:点击item7的“×”,右边item7消失,左边item7出现
5、重置时,页面回复初始化状态
实现方法:
1、左右json格式如下:
left=[
{"name": "一级","indexid": 1},
{"name": "item1", "id": 1,"indexid": 2},
{"name": "item2","id": 2,"indexid": 3},
{"name": "二级","indexid": 4},
{"name": "item3","id": 3,"indexid": 5},
{"name": "item4","id": 4,"indexid": 6}
...
];
right=[
{"name": "item8","id": 8,"indexid": 10},
{"name": "item7","id": 7,"indexid": 9}
]
2、dom原始使用flex布局,拖拽时使用Vue.Draggable插件,
3、一开始左边加载所有的items,右边加载展示的items,注意:左边要过滤掉(隐藏)右边有的items,参考filterComs(left,right)方法;
在渲染dom、移动、删除时,通过操作dom来实现展示与隐藏;
4、左边draggle插件,:group="{ name: 'dragobj', pull: 'clone', put: false}"
{ name: 'dragobj'取相同名字的可以来回拖拽;pull: 'clone'从左向右克隆,后面用右边draggle插件的dragChangeR()方法让左侧数据隐藏了,left并不是真正的删除这条数据;put: false 禁止从右向左拖放数据 }
:move="checkMove" 移动时绑定checkMove方法,判断是上下还是向右移动,上下时,不执行拖拽;向右时,执行
5、右边draggle插件的deleteItme(element,index)方法实现删除时,right数据-1,左侧显示该条数据
6、【重置】时,重新调用this.filterComs(this.left,this.right);即可
7、问题:从左往右移动时,右侧一直会出现items的name值,拖拽结束后,name值消失,
解决方法:左右分别绑定一个v-bind="dragOptionsL",v-bind="dragOptionsR"
8、问题:当右侧没有任何的items时,需要给右侧v-for循环的父元素指定一个min-height,否则从左侧拖到右侧时,没有接收的地方,则拖放失效
<template>
<div class="box">
<div class="dragset-msg">请将左侧内容拖到右侧进行配置</div>
<!-- 1 左边指标 -->
<draggable tag="ul" class="lul"
v-bind="dragOptionsL"
:move="checkMove"
:list="left"
:group="{ name: 'dragobj', pull: 'clone', put: false}">
<li v-for="element in left" :key="element.name"
:class="element.id?'dragindex':'dragtheme'"
:ref="`li${element.indexid}`">
{{ element.name }}
</li>
</draggable>
<!-- 2 右边展示区 -->
<draggable tag="div" class="rconfig"
group="dragobj"
:list="right"
v-bind="dragOptionsR"
@change="dragChangeR"
@start="drag = true"
@end="drag = false">
<transition-group type="transition" :name="!drag ? 'flip-list' : null" tag="ul" class="rul">
<li class="showindex" v-for="(element,index) in right" :key="element.name" >
{{ element.name }}
<input type="button" class="btnindex" @click.stop="deleteItme(element,index)">
</li>
</transition-group>
</draggable>
</div>
</template>
<script>
import draggable from "vuedraggable";
import Vue from "vue";
export default {
components: { draggable },
data() {
return {
blnShowDlg: false,
dlgType: "add", // 窗口类型
titleName: "", // 窗口标题显示
settingData: {}, //获取左右配置数据
dataFormStore:{},//保存数据
left:[],//左边数据
right:[],//右边数据
drag:false,
};
},
computed: {
dragOptionsL() {
return {
disabled: false,
ghostClass: "ghostL"//注意:在左侧上下移动时,使用这个类;移动到右侧时,使用ghostR类!!!
};
},
dragOptionsR() {
return {
animation: 500,
disabled: false,
ghostClass: "ghostR"//注意:在右侧上下移动时,使用这个类;
};
}
},
methods: {
/** 1、显示弹框 row不传为添加 传参为修改 */
showDlg(row) {
this.titleName = "页面配置";
this.dlgType = "edit";
this.blnShowDlg = true;
this.dataFormStore = this.$common.deepCopy(row);//存储原始数据
this.left=row.left;
this.right=row.right;
this.restoreForm();
},
// 2 左侧list移动,禁止在左侧上下移动
checkMove(evt){
let classObj=evt.to.className;
if(evt.draggedContext.element.id===""){
return false;
}else if(classObj.indexOf("lul")>-1){
return false;
}
},
// 2.1 拖拽事件,添加时隐藏左侧添加的数据
dragChangeR(evt) {
if(evt.added){//这时候已经添加了
this.$refs[`li${evt.added.element.indexid}`][0].style.display='none';
}
},
// 3 删除
deleteItme(element,index){
this.right.splice(index,1);
this.$refs[`li${element.indexid}`][0].style.display='block';
},
// 4 取消
closeDialog() {
this.blnShowDlg = false;
},
// 5 关闭
hidDlg() {
this.blnShowDlg = false;
},
/** 6 修改-还原 */
restoreForm() {
this.left=this.$common.deepCopy(this.dataFormStore.left);
this.right=this.$common.deepCopy(this.dataFormStore.right);
this.filterComs(this.left,this.right);
},
/** 7 添加/保存 */
submitForm() {
let newright=this.right;
let rlens=this.right.length;
if(rlens>0){
let idArr=[];
for(let i=0;i<rlens;i++){
idArr.push(newright[i].indexid);
}
this.$emit("doSaveRow",idArr); // 把id数组传递过去
}else{
this.$HiAlert.showFail(this.$HiAlert.getMsgText("至少选择一个菜单"));
}
},
// 8 过滤不显示的左侧item
filterComs(left,right){
if(right.length > 0){
// 初始化,全置为blcok,后面根据right数据过滤显示
for(let i=0;i< left.length;i++){
this.$nextTick(() => {
this.$refs[`li${left[i].indexid}`][0].style.display='block';
});
}
for(let i=0;i< right.length;i++){
let filteritem=left.filter((element,index,self)=>{
return element.indexid==right[i].indexid;
});
// 右侧有数据时,dom生成之后再来渲染,否则会报错:cannot read property '0' of undefined
this.$nextTick(() => {
this.$refs[`li${filteritem[0].indexid}`][0].style.display='none';
});
}
}
}
}
};
</script>
<style lang="stylus" scoped>
//应用样式文件
.ghostL{
opacity:0.5;
width:230px;
}
.ghostR{
opacity:0;
width:230px;
}
</style>