• vue 仿zTree折叠树


    需求: 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;  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;
             1px;
            height: 13px;
            border-left: 1px dashed #FFF;
        }
        .line-10 {
            position: absolute;
            left: -10px;
            top: 0;
            display: inline-block;
             1px;
            height: 15px;
            border-left: 1px dashed #FFF;
        }
        .line-10-last {
            position: absolute;
            left: -11px;
            top: 0;
            display: inline-block;
             1px;
            height: 15px;
            border-left: 1px dashed #FFF;
        }
        .line-7 {
            position: absolute;
            left: -10px;
            top: 15px;
            display: inline-block;
             7px;
            height: 1px;
            border-bottom: 1px dashed #FFF;
        }
        .line-25 {
            position: absolute;
            left: -10px;
            top: 15px;
            display: inline-block;
             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;
             auto;
            height: 14px;
        }
        .arrow:hover {
            cursor: pointer;
        }
        .select-icon {
            display: inline-block;
             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;
             auto;
        }
        .expand-icon:hover {
            cursor: pointer;
        }
        .init-line {
            position: absolute;
            left: 7px;
            top: -3px;
            display: inline-block;
             0;
            height: 8px;
            box-sizing: border-box;
            border-left: 1px dashed #FFF;
        }
        .outer {
            position: absolute;
            left: 7px;
            top: 2px;
            display: inline-block;
             14px;
            height: 20px;
            box-sizing: border-box;
            border-left: 1px dashed #FFF;
            .inner {
                display: inline-block;
                 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;
             14px;
            height: 13px;
            top: 2px;
            box-sizing: border-box;
            border-left: 1px dashed #FFF;
            .inner-sub {
                display: inline-block;
                 10px;
                height: 0;
                box-sizing: border-box;
                border-bottom: 1px dashed #FFF;
                position: relative;
                top: 0px;
            }
        }
    }
    </style>
  • 相关阅读:
    WebService中Dataset的压缩序列化和解压反序列化(DataSetSurrogate的使用)
    IOleControl 代码一,测试有问题,备忘
    关于Stream和byte之间的转换 .
    webbrowser 实现IOleControl接口2
    JavaScropt获取网页、浏览器、屏幕高度和宽度
    Oracle默认的用户名和密码
    window.showModalDialog()用法及注意事项
    Android1.6开发环境配置
    string与stream互相转换
    GirdView实现单选、FooterTemplate实现新建和PagerTemplate实现分页
  • 原文地址:https://www.cnblogs.com/min77/p/14205349.html
Copyright © 2020-2023  润新知