VUE+ElementUI實現左側為樹形結構、右側無層級結構的穿梭框


工作中遇到一個需求,需要將一個數據選擇做成穿梭框,但是要求穿梭框左側為樹形結構、右側為無層級結構的數據展示,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() {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'
}

父組件中引用方式:

<tree-transfer ref="treeTransfer" :datas="selectItem" :defaultProps="defaultProps" ></tree-transfer>

學到的小技巧:ElementUI中如果要dialog不緩存其中的內容只需要給它外部套一個div然后添加v-if屬性即可,值和控制dialog顯隱的值相同。

 注:后續使用需要按照自己的數據字段名替換掉parameterInfoList


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM