工作中遇到一個需求,需要將一個數據選擇做成穿梭框,但是要求穿梭框左側為樹形結構、右側為無層級結構的資料展示,ElementUI自身無法在穿梭框中新增樹形結構,網上搜到了大佬封裝的外掛但是對於右側的無樹形結構一點還是不太滿足,於是自己基於ElementUI和VUE2.X做了一個小元件,優化的地方還很多,但是能夠基本滿足業務需求,後面有時間也會努力去改的更加靈活。我是新手程式設計師,大佬們看到了有什麼可以優化的地方希望能夠指正。

<template>
<!-- 自定義樹形穿梭框元件、理論上左右均可選擇是否為樹形結構,目前固定為左側樹形、右側無層級結構 -->
<div class="tree-transfer">
<!-- 穿梭框左側 -->
<div class="tree-transfer-left">
<!-- 左側採用element-ui的el-tree -->
<el-tree
ref="treeLeft"
:data="dataLeft"
show-checkbox
node-key="id"
:props="defaultProps">
</el-tree>
</div>
<!-- 穿梭框中間按鈕區域 -->
<div class="tree-transfer-middle">
<el-button circle type="info" icon="el-icon-arrow-left" @click="remove"></el-button>
<el-button circle type="info" icon="el-icon-arrow-right" @click="add"></el-button>
</div>
<!-- 穿梭框右側 -->
<div class="tree-transfer-right">
<!-- 右側直接放置結果 -->
<!-- 這裡也採用tree結構,預設是對資料進行處理使得沒有樹形結構,也可以選擇有樹形結構 -->
<el-tree
ref="treeRight"
:data="dataRight"
show-checkbox
node-key="id"
:props="defaultProps">
</el-tree>
</div>
</div>
</template> <script>
export default{
props:['datas','defaultProps'],
data(){
return{
yuansiData:[],
dataLeft:[],
dataRight:[]
}
},
mounted() {
console.log(this.datas)
this.dataLeft = this.datas
this.yuansiData = JSON.parse(JSON.stringify(this.datas))
},
methods:{
add(){
// 定義一個遞迴過濾的方法,用來刪掉父級中給的元素
// 獲取所有選中的項並且去掉父級
let list = this.$refs.treeLeft.getCheckedNodes()
// 走原始資料中刪掉已經選擇的
// 1.父級的刪除
const parList = list.filter(item=>{
return item.parameterInfoList
})
for(let item1 of parList){
let index = this.dataLeft.findIndex(item2=>{
return item2.id == item1.id
})
if(index>=0){
this.dataLeft.splice(index,1)
}
}
// 2.子級的刪除
list = list.filter((item=>{
return !item.parameterInfoList
}))
// 這裡做了三重迴圈,如果有可能需要對其進行優化
for(let item of list){
for(let ind in this.dataLeft){
if(this.dataLeft[ind].parameterInfoList.length){
let index = this.dataLeft[ind].parameterInfoList.findIndex(item2=>{
return item2.id == item.id
})
if(index>=0){
this.dataLeft[ind].parameterInfoList.splice(index,1)
}
}
}
}
this.$refs.treeLeft.setCheckedNodes([])
// 將選擇的項新增到右側
this.dataRight.push(...list)
},
remove(){
// 從右側移除時的方法
// 1.從右側刪除選中的資料
let list = this.$refs.treeRight.getCheckedNodes()
for(let item of list){
let index = this.dataRight.findIndex(item2=>{
return item.id == item2.id
})
if(index>=0){
this.dataRight.splice(index,1)
}
}
// 2.把右側刪除的資料新增給左側,但是要注意父級的問題
this.dataLeft = JSON.parse(JSON.stringify(this.yuansiData))
for(let index in this.dataLeft){
// 如果有子級去刪除子級
for(let item of this.dataRight){
let ind = this.dataLeft[index].parameterInfoList.findIndex(item2=>{
return item2.id == item.id
})
if(ind>=0){
this.dataLeft[index].parameterInfoList.splice(ind,1)
}
}
this.dataLeft = this.dataLeft.filter(item2=>{
return item2.parameterInfoList.length!=0
})
}
},
getResult(){
return this.dataRight
}
}
}
</script> <style scoped lang="less">
.tree-transfer{
display: flex;
min-height: 250px;
.tree-transfer-left{
min-width: 200px;
border:1px #E5E5E5 solid;
border-radius: 10px;
padding: 10px;
}
.tree-transfer-middle{
display: flex;
justify-content: center;
align-items: center;
min-width: 120px;
}
.tree-transfer-right{
min-width: 200px;
border:1px #E5E5E5 solid;
border-radius: 10px;
padding: 10px;
}
}
</style>

父元件需要傳遞帶層級結構的datas,和ElementUI中tree的props。

這裡使用的datas中的唯一標識是id,子元素放在parameterInfoList欄位中。

defaultProps: {
children: 'parameterInfoList',
label: 'name'
}