想做一个异步加载的 tree-table ,收起节点的方法想不明白了求教

效果图如下:

clipboard.png

整体思路,后台返回的每行数据都会有一个字段,hasChildren 我用来判断是否显示 ‘+’,第一次加载不传id,拿到根节点数据。

点击加号,用当前行id查询数据,获取下级数据,调用方法,在原数据基础上增加子节点数据。

             JSON.parse(res.data.ext).reverse().forEach(item => {
                            this.data.splice(index + 1,0,item)
             })

我的问题在于,不知道点击 ‘-’ 执行怎样的方法了。

我最初是用 this.data = this.data.filter(item => item.pid != row.id) 但是这样会有一个问题,子节点的子节点如果展开了,这种方法就不行了。

求教应该怎么处理呢?

阅读 3.8k
3 个回答

最后解决了,思路是在收起的动作时,用递归获取当前操作行下的所有子节点id,最后根据这id的数组,对源数据进行晒出。

封装了一个异步加载数据的tree-table组件 贴下代码。 感谢回答问题的朋友。
效果图:

clipboard.png

myAsynTreeTable.vue

<template>

<el-table id="asynTable" :data="data"
          ref="asynTable"
          :header-cell-style="{padding:'1px 0',background:'#dfebf9',fontSize:'12px'}"
          :cell-style="{padding:'3px 0'}"
          size="mini"
          v-bind="$attrs"
          v-loading="loading"
          :empty-text="emptyText">

    <el-table-column
            type="index"
            :label="$t('common.order')">
        width="50">
    </el-table-column>
    <el-table-column v-for="(column, index) in columns" :key="column.value" :label="column.text"
                     :width="column.width">
        <template slot-scope="scope">

            <div v-if="column.showOpen">

                <span :style="'margin-left:'+ scope.row.level*10 + 'px'" class="ms-tree-space"/>
                <span v-if="iconShow(scope.row)" class="tree-ctrl" @click="toggleExpanded(scope.row,scope.$index)">
                      <i v-if="!scope.row._expanded" class="el-icon-plus"/>
                      <i v-else class="el-icon-minus"/>
                    </span>
                {{ scope.row[column.value] }}
            </div>
            <span v-else>
                    {{ scope.row[column.value] }}
                </span>
        </template>
    </el-table-column>
    <slot/>
</el-table>

</template>

<script>

export default {
    name: 'treeTable',
    props: {
        columns: {
            type: Array,
            default: () => []
        },
        url:{
            type:String,
            default: () => ''
        }
    },
    data() {
        return {
            data:[],
            radio: '',
            radioName: 'a1',
            emptyText: '加载中...',
            loading:false
        }
    },
    mounted() {
        var that = this;
        //解决表格表头错位的问题
        setTimeout(function () {
            var asynTable = document.getElementById('asynTable');
            if (asynTable) {
                var thGutter = asynTable.getElementsByClassName('gutter')[0];
                thGutter.style.display = 'table-cell';
            }
        }, 500)
        window.onresize = function () {
            setTimeout(function () {
                var asynTable = document.getElementById('asynTable');
                if (asynTable) {
                    var thGutter = asynTable.getElementsByClassName('gutter')[0];
                    thGutter.style.display = 'table-cell';
                }
            }, 500)
        }
        setTimeout(function () {
            that.hideRadioLabel();//隐藏radiobutton的LABEL
        }, 0)

        this.getTreeData()

    },
    methods: {
        getTreeData(){
            this.$myHttp({
                method: 'POST',
                url: this.permissionPrefix + this.url,
                data: {
                    entity: {
                        lang: this.$i18n.locale
                    }
                }

            }).then(res => {
                if (res.data.ext) {
                    this.data = JSON.parse(res.data.ext)
                }

            });
        },
        // 切换下级是否展开
        toggleExpanded: function (row, index) {

            //将当前行打标记(已展开或已收起)
            row._expanded = !row._expanded

            //根据收起、展开处理两种情况
            this.handleTableData(row, index)

            //主动触发视图,使_expanded在视图层生效
            this.iconShow(row)
        },
        handleTableData(row, index) {

            if (row._expanded) {
                //展开下级数据,通过id、层级,获取下级数据
                this.expandSub(row,index)
            } else {

                //折叠下级数据
                let data = this.data

                function findAllChild(parentId) {
                    let childrens = [];
                    function runTime(id) {
                        for (let i = 0; i < data.length; i++) {
                            if (data[i].pid === id) {
                                childrens.push( data[i].id);
                                runTime( data[i].id );
                            }
                        }
                    }
                    runTime(parentId);
                    return childrens;
                }


                //递归找到选中行 子节点全部数据,过滤掉
                findAllChild(row.id).forEach(item => {
                    this.data = this.data.filter(subItem => subItem.id != item)
                })

            }

        },
        expandSub(row,index){
            this.loading = true
            this.$myHttp({
                method: 'POST',
                url: this.permissionPrefix + this.url,
                data: {
                    entity: {
                        lang: this.$i18n.locale,
                        pid: row.id,
                        level:row.level
                    }
                }

            }).then(res => {
                this.treeTableData = [];
                if (res.data.ext) {
                    //反转数据,将数据拼接至当前选中行下面
                    JSON.parse(res.data.ext).reverse().forEach(item => {
                        this.data.splice(index + 1,0,item)
                    })
                }
                this.$nextTick(_ => {
                    this.loading = false
                })

            });
        },
        // 图标显示
        iconShow(row) {
            return row.hasChildren == 'true'
        },
        hideRadioLabel() {
            var labels = document.getElementsByClassName('el-radio__label');
            for (var i = 0; i < labels.length; i++) {
                labels[i].style.display = 'none';
            }

        }
    }
}

</script>

<style lang="less" rel="stylesheet/less" scoped>

@color-blue: #2196F3;
@space-width: 18px;
.ms-tree-space {
    position: relative;
    top: 1px;
    display: inline-block;
    font-style: normal;
    font-weight: 400;
    line-height: 1;
    width: @space-width;
    height: 14px;
    &::before {
        content: ""
    }
}

.tree-ctrl{
    position: relative;
    cursor: pointer;
    color: @color-blue;
    margin-left: -@space-width;
}

</style>

el-table尝试一下

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题