需求: vue实现仿zTree折叠树,此文章仅作为记录文档。

实现:

<template>
    <div class="line-tree">
        <div v-for="(item, index) in treeData" :key="index" class="single-content" :class="treeLine ? getSecond(item) : ''">
            <span></span>
            <p class="parent-node">
                <!-- treeLine 是否显示连接线 -->
                <span v-if="treeLine"> 
                    <span class="line-7" v-if="level !== 0 && (item.children && item.children.length)"></span>
                    <span class="line-25" v-if="level !== 0 && (!item.children || !item.children.length)"></span>
                    <span v-if="item.last" class="line-10-last"></span>
                </span>

                <span v-if="item.children && item.children.length && item.name" class="arrow-icon" @click="changeState(item)">
                    <img src="../../../../static/images/jurisdiction-add.png" v-if="!item.expand" alt="+" class="expand-icon">
                    <img src="../../../../static/images/jurisdiction-cut.png" v-else alt="-" class="expand-icon">
                </span>
                <span v-else>
                    <i style="display: inline-block; height: 14px; width: 16px; position: relative; top: 2px;"></i>
                </span>
                <span v-if="keyTree == 'role'">
                    <span class="city" :class="{'active-name' : treeActive === item.id}" @click="item.children.length === 0 ? skipCost(item) : parentClick(item)">{{item.name}}</span>
                </span>
                <span v-else>
                    <span class="city" :class="{'active-name' : treeActive === item.id}" @click="(item.children.length === 0 || item.deep === 1) ? skipCost(item) : parentClick(item)">{{item.name}}</span>
                </span>
            </p>

            <div v-if="item.children && item.children.length && item.expand" class="sub-content" :class="treeLine ? cancelBor(item) : ''">
                <permission-base-tree @skipCost="skipCost" :currentDep="currentDep" :level="level + 1" :treeData="item.children" :keyTree="keyTree"></permission-base-tree>
            </div>
        </div>
    </div>
</template>
<script>
import { mapGetters, mapMutations } from "vuex";
export default {
    name: 'permission-base-tree',
    data() {
        return {}
    },
    props: {
        treeData: {
            type: Array,
            default: () => []
        },
        level: {
            type: Number,
            default: () => 0
        },
        currentDep: {
            type: Number,
            default: () => 0
        },
        keyTree: {
            type: String,
            default: () => ""
        },
        treeLine: {
            type: Boolean,
            default: () => false
        }
    },
    computed: {
        ...mapGetters(["treeActive"])
    },
    watch: {
        treeData: {
            handler(newVal, oldVal) {
                if (newVal) {
                    this.treeData = newVal;
                } 
            },
            deep:true
        },
    },
    created() {
    },
    methods: {
        ...mapMutations({
            setActive: 'SET_treeActive'
        }),
        skipCost(item) {
            this.setActive(item.id);
            this.$emit('skipCost', item);
        },
        parentClick(item) {
            this.setActive(item.id);
            item.expand = !item.expand;
        },

        /**
         * 改变生效状态
         */
        changeEffect(item, sub) {
            this.$emit('changeEffect', [item, sub]);
        },
        /**
         * 添加
         */
        add(item) {
            console.log('item', item);
            this.$emit('add', item);
        },
        /**
         * 编辑
         */
        edit(item, sub) {
            this.$emit('edit', [item, sub]);
        },
        /**
         * 删除
         */
        deleteWarning(item, sub) {
            this.$emit('deleteWarning', [item, sub]);
        },
        changeSelect(item, index){
            item.select = !item.select;
            if (item.select) {  //  子类全选
                if (item.children && item.children.length) {
                    // 子类变为选中状态
                    this.transferTrue(item.children, true);
                }
                console.log('select',[true, item.levelList]);
                this.$emit('changeParent', [true, item.levelList]);
            } else {    //  取消全选
                if (item.children && item.children.length) {
                    this.transferTrue(item.children, false);
                }
                this.$emit('changeParent', [false, item.levelList]);
            }
        },
        changeParent(val) {
            if (val[0]) {  //  子类为true
                let flag = true;
                let arr = val[1].slice(0, val[1].length - 1);
                let idx = arr[arr.length - 1];
                for (let i = 0; i < this.treeData[idx].children.length; i++) {
                    if (!this.treeData[idx].children[i].select) {
                        flag = false;
                        break;
                    }
                }
                if (flag) {
                    this.treeData[idx].select = true;
                } else {
                    this.treeData[idx].select = false;
                }
                this.$emit('changeParent', [true, this.treeData[idx].levelList])
            } else {
                let arr = val[1].slice(0, val[1].length - 1);
                let idx = arr[arr.length - 1];
                this.treeData[idx].select = false;
                this.$emit('changeParent', [false, this.treeData[idx].levelList],val[2]);
            }
        },
        cancelBor(item) {
            if (!item.last) {
                return 'add-second';
            }
        },
        getSecond(item) {
            if (!item.last) {
                return 'add-second';
            }
        },
        
        getMargin(item) {
            let currentLevel = item.level;
            if (item.children && item.children.length) {
                return {
                    marginRight: (this.currentDep - item.level - 1) * 18 + 'px'
                }
            }
        },
        transferTrue(arr, flag) {
            arr.forEach((item, index) => {
                item.select = flag;
                if (item.children && item.children.length) {
                    this.transferTrue(item.children, flag);
                }
            })
        },
        changeState(item) {
            item.expand = !item.expand;
        }
    }
}
</script>
<style lang="less" scoped>
.line-tree {
    font-size: #000;
    .single-content {
        position: relative;
        left: -11px;
        padding-left: 11px;
    }
    .single-troditional {
        display: inline-block;
        height: 24px;
        line-height: 24px;
        background: #B1D6FF;
        margin-right: 10px;
        padding: 0 5px;
        color: #000;
        border-radius: 3px;
    }
    .common-img {
        display: inline-block;
        margin-left: 5px;
    }
    .common-img:hover {
        cursor: pointer;
    }
    .add-continal {
        color: #0847A9;
        margin-right: 15px;
    }
    .add-continal:hover {
        cursor: pointer;
    }
    .add-second {
        border-left: 1px dashed #FFF;
    }
    .line-15 {
        position: absolute;
        left: -10px;
        top: 15px;
        display: inline-block;
        width: 1px;
        height: 13px;
        border-left: 1px dashed #FFF;
    }
    .line-10 {
        position: absolute;
        left: -10px;
        top: 0;
        display: inline-block;
        width: 1px;
        height: 15px;
        border-left: 1px dashed #FFF;
    }
    .line-10-last {
        position: absolute;
        left: -11px;
        top: 0;
        display: inline-block;
        width: 1px;
        height: 15px;
        border-left: 1px dashed #FFF;
    }
    .line-7 {
        position: absolute;
        left: -10px;
        top: 15px;
        display: inline-block;
        width: 7px;
        height: 1px;
        border-bottom: 1px dashed #FFF;
    }
    .line-25 {
        position: absolute;
        left: -10px;
        top: 15px;
        display: inline-block;
        width: 25px;
        height: 1px;
        border-bottom: 1px dashed #FFF;
    }
    .sub-content {
        margin-left: 7px;
        padding-left: 11px;
    }
    .add-border {
        border-left: 1px dashed #FFF;
    }
    .parent-node {
        height: 30px;
        vertical-align: middle;
        position: relative;
        white-space: nowrap;
    }
    img {
        vertical-align: middle;
    }
    .file-icon {
        display: inline-block;
        width: auto;
        height: 14px;
    }
    .arrow:hover {
        cursor: pointer;
    }
    .select-icon {
        display: inline-block;
        width: 15px;
        height: 15px;
    }
    .last-content {
        padding-left: 30px;
    }
    .select-box:hover {
        cursor: pointer;
    }
    .city {
        font-size: 14px;
        color: #000;
        display: inline-block;
        height: 30px;
        line-height: 30px;
    }
    .active-name {
        color: #0847A9;
        font-weight: bold;
        text-decoration: underline;
    }
    .city:hover {
        cursor: pointer;
    }
    .expand-icon {
        display: inline-block;
        height: 14px;
        width: auto;
    }
    .expand-icon:hover {
        cursor: pointer;
    }
    .init-line {
        position: absolute;
        left: 7px;
        top: -3px;
        display: inline-block;
        width: 0;
        height: 8px;
        box-sizing: border-box;
        border-left: 1px dashed #FFF;
    }
    .outer {
        position: absolute;
        left: 7px;
        top: 2px;
        display: inline-block;
        width: 14px;
        height: 20px;
        box-sizing: border-box;
        border-left: 1px dashed #FFF;
        .inner {
            display: inline-block;
            width: 10px;
            height: 0;
            box-sizing: border-box;
            border-bottom: 1px dashed #FFF;
            position: relative;
            top: 0px;
        }
    }
    
    .outer-sub {
        position: absolute;
        left: 7px;
        display: inline-block;
        width: 14px;
        height: 13px;
        top: 2px;
        box-sizing: border-box;
        border-left: 1px dashed #FFF;
        .inner-sub {
            display: inline-block;
            width: 10px;
            height: 0;
            box-sizing: border-box;
            border-bottom: 1px dashed #FFF;
            position: relative;
            top: 0px;
        }
    }
}
</style>

 

posted on 2020-12-29 10:50  羽丫头不乖  阅读(321)  评论(0编辑  收藏  举报