vue jsx 封装Table 表格+Tree 树形控件

1,314 阅读3分钟

背景介绍

通过表格展示树的层级,可通过对树的勾选对每一个界面的dom元素进行控制,控制程度可精确到组件/标签

图片预览

表格树

需求分析

  1. 根据树形结构获取层级(列数)
  2. 根据数据动态控制表格列数
  3. 格式化表格内容
  4. 将单元格内容(扁平化)转为结构化数据
  5. 勾选/取消勾选时关联相关层级

树形结构设置层级

层级部分数据如下图所示

层级部分数据

设置第一层

data(){
    return {
        index: '', //自定义列内容出现index未定义报错,需加上index参数
        numberList:[],
        num:0
    }
}

deepTableDataFirstLevel(data){ //setting first level 第一层
    var that = this;
    that.num ++;
    if(that.numberList.indexOf(that.num) == -1){
        that.numberList.push(that.num);
    }
    data.filter(v=>{
        that.$set(v,'level',that.num);
        that.$set(v,'parentId',0);
        if(v.children && v.children.length > 0){
            that.deepTableDataOrderLevel(v.children,(that.num+1),v.id)
        }
    })
}

num为层级

第一层默认parentId为0

numberList存储层级(储存标识防止重复层级)

设置其他层

deepTableDataOrderLevel(data,num,id){ //setting order level 其他层级
    var that = this;
    if(that.numberList.indexOf(num) == -1){
        that.numberList.push(num);
    }
    data.filter(v=>{
        that.$set(v,'level',num);
        that.$set(v,'parentId',id);
        if(v.children && v.children.length > 0){
            that.deepTableDataOrderLevel(v.children,(num+1),v.id)
        }
    })
}

data为父级列表

父级列表遍历设置相同层级

每到下一层层级+1

deepTableDataOrderLevel方法每执行一次就把当前对象(存在children情况下)递归该对象chilren参数列表并给其对象设置层级

将相同层级数据转换为table列表数据

转换第一层

data(){
    return {
        num:0,
        index: '', //自定义列内容出现index未定义报错,需加上index参数
        columnData:[],
        levelObj:{}
    }
}

handleTable(data){ //setting first level 第一层
    var that = this;
    that.columnData = [];
    that.levelObj = {};

    data.filter((v,index)=>{
        that.$set(that.columnData,index,{label:v.label,value:v.id,id:v.id,parentId:v.parentId})
        if(v.children && v.children.length > 0){
            that.numberList.filter(n=>{
                that.levelObj[('level'+n)] = [];
            })
            that.$set(that.columnData[index],'level1',[{label:v.label,value:v.id,id:v.id,parentId:v.parentId,checked:false}]);
            that.deepTableList(v.children,index);
        }
    })

}

将归属于第一层的数据以level+层级以数组形式添加到columnData并设置默认为取消的勾选参数

转换其他层

deepTableList(data,num){ //setting order level 其他层级
    var that = this;
    data.filter(v=>{
        if(that.numberList.indexOf(v.level) > -1){
            that.levelObj['level'+v.level].push({label:v.label,value:v.id,id:v.id,parentId:v.parentId,checked:false});
            that.$set(that.columnData[num],'level'+v.level,that.levelObj['level'+v.level]);
        }
        if(v.children && v.children.length > 0){
            that.deepTableList(v.children,num)
        }
    })
}

将归属于其他层的数据以level+层级以数组形式添加到columnData并设置默认为取消的勾选参数

动态控制表格列数并格式化内容

这里使用渲染函数jsx进行处理

<template>
    <div class="tableTree">
        <table-column :node="columnData" :num="numberList" :key="index" />
    </div>
</template>
components:{
    TableColumn:{
        props:{
            node:{
                default(){
                    return {}
                }
            },
            num:{
                default(){
                    return []
                }
            },
        },
        render(h){
            const superParams = this.$parent.superParams;
            const parent = this.$parent;
            const node = this.node;
            const num = this.num;
            let tableRowList = []; //防止重复数据
            let rowIdList = [];
            const renderContent = (row, column, cellValue, index) => { //格式化内容
                //()=>parent.checkMenu(row) 防止立刻触发
                cellValue && cellValue.filter(v=>{
                    if(rowIdList.indexOf(v.id) == -1){
                        rowIdList.push(v.id);
                        tableRowList.push(v);
                    }
                })
                return cellValue && cellValue.map((item,index) => <el-checkbox v-on:change={()=>superParams.checkMenu(item,tableRowList)} v-model={item.checked}>{item.label}</el-checkbox>)
            }
            const templateNode =  
             <el-table data={node} border height={600}>
                {
                    num.map((v,index)=> <el-table-column width={v > 2 ? 350 : 180} prop={'level'+v} label={'level'+v} key={index} formatter={renderContent} />)
                }
            </el-table>

            return (templateNode);
        }
    }
}

superParams为最高层组件参数通过(inject: ['superParams'])引入

parent为父级参数

num为数据的层级

通过num实现对el-table-column列数的展示

formatter格式化内容

cellValue为单元格内容,这里将单元格内容设置为Checkbox 多选框

checkMenu为最高级组件方法并携带当前行参数(row),所有row参数(tableRowList)(扁平化结构)

由于cellValue单元格内容为单独的对象形式的数据,需要对其转换为结构化,并保证该checked为响应式

将单元格内容(扁平化)转为结构化数据

勾选后对数据进行处理

data(){
    return {
        editForm: {
            menuIds:[]
        },
        deepPermTreeData:[],
        rowTree:[],
        levelParentIdList:[]
    }
}
checkMenu(row,tableRowList){ //id必须唯一(否则会出现无法关联的问题)
    this.editForm.menuIds = [];
    this.tableRowTree(tableRowList);
    this.deepPermTreeData = tableRowList;
    this.$set(row,'firstSelect',row.id);
    this.searchParent(row);
    tableRowList = this.rowTree;
    //对已有的数据进行回显
    this.deepPermTreeData.filter(v=>{
        if(v.checked){
            this.editForm.menuIds.push(v.id);
        }
    })
}

扁平化结构转换树形结构

import _ from 'lodash' //需引入
//初始化树形结构
tableRowTree(list){
    var that = this;
    that.rowTree = [];
    list.filter(v=>{
        if(v.parentId == 0){
            that.rowTree.push(v);
        }
    })
    that.tableRowChildrenTree(that.rowTree,list);
    list = that.rowTree;
},
//扁平化结构转为树形结构
tableRowChildrenTree(data,list){ 
    var that = this;
    data.filter(v=>{
        if(_.filter(list,['parentId',v.id]).length > 0){
            that.$set(v,'children',_.filter(list,['parentId',v.id]));
        }
        if(v.children){
            that.tableRowChildrenTree(v.children,list);
        }
    })
}

勾选/取消勾选时关联相关层级

从选中方法开始

//选中勾选框
checkMenu(row,tableRowList){ //id必须唯一(否则会出现无法关联的问题)
    this.editForm.menuIds = [];
    this.tableRowTree(tableRowList);
    this.deepPermTreeData = tableRowList;
    his.$set(row,'firstSelect',row.id);
    this.searchParent(row);
    tableRowList = this.rowTree;
    //对已有的数据进行回显
    this.deepPermTreeData.filter(v=>{
        if(v.checked){
            this.editForm.menuIds.push(v.id);
        }
    })
    //console.log(this.editForm.menuIds);
},

//查找父级id
searchParent(row){
    this.deepPermTreeData.filter(v=>{
            if(row.parentId == 0){ //当前级别为最高级别
                if(row.id == v.parentId){ //当前最高级别的子级
                    if(row.checked){ //当前元素为勾选状态
                        this.$set(v,'checked',true); //对当前元素的子级进行勾选
                        this.checkList = [];
                        this.deepCheckedChildList(row.children);
                        this.checkedRoleList(this.checkList);
                    }else { //当前元素为取消勾选状态
                        this.$set(v,'checked',false); //对当前元素的子级取消勾选
                        this.checkList = [];
                        this.deepCheckedChildList(row.children);
                        this.unCheckedRoleList(this.checkList);
                    }
                }
            }else {
                if(v.id == row.parentId){ //当前级别不是最高级别/当前元素父级
                    if(row.checked){ //当前元素已勾选
                        this.$set(v,'checked',true); //勾选父级
                        this.levelParentIdList = [];
                        this.searchLevelParent(this.deepPermTreeData,v.parentId);
                        this.checkedRoleList(this.levelParentIdList);
                        this.checkList = [];
                        this.deepCheckedChildList(row.children);
                        this.checkedRoleList(this.checkList);
                    }else{ //当前元素取消勾选
                        this.deepunCheckedRoleList(v,row.id);
                        this.checkList = [];
                        this.deepCheckedChildList(row.children);
                        this.unCheckedRoleList(this.checkList);
                    }
                }

            }
    })
},
//逆向查找各层父节点
searchLevelParent(data,parentId){
    var that = this;
    data.filter(v=>{
        if(v.id == parentId){
            that.levelParentIdList.push(v.id);
            that.searchLevelParent(data,v.parentId); //存在上一层则继续查找父级
        }else if(v.children && v.children.length > 0){
            that.searchLevelParent(v.children,parentId);
        }
    })
},
//勾选对应的权限
checkedRoleList(idList){
    this.deepPermTreeData.filter(v=>{
        if(idList.indexOf(v.id) > -1){
            this.$set(v,'checked',true); 
        }
    })
},
//取消勾选对应的权限
unCheckedRoleList(idList){
    this.deepPermTreeData.filter(v=>{
        if(idList.indexOf(v.id) > -1){
            this.$set(v,'firstSelect','');
            this.$set(v,'checked',false); 
        }
    })
},
//递归遍历
deepunCheckedRoleList(list,id){
    var isChecked = [];
    var unChecked = [];
    isChecked = _.filter(list.children,['checked',false]); //同级节点未勾选列表
    unChecked = _.filter(list.children,['checked',true]); //同级已勾选的节点
    if(isChecked.length == list.children.length){ //同级元素都取消勾选
        var listId = [];
        listId.push(list.id);
        this.unCheckedRoleList(listId); //取消勾选父级
        if(list.parentId != 0){
            var parentObj = this.searchRoleList(list.parentId); //找出父级的同级
            this.deepunCheckedRoleList(parentObj,parentObj.id);
        }
    }else {
        var list = [];
        list.push(id);
        //this.unCheckedRoleList(list);
    }
},
//找到对应父节点列表
searchRoleList(id){
    var list = {};
    this.deepPermTreeData.filter(v=>{
        if(id == v.id){
            list = v;
        }
    })
    return list;
},
//勾选子列表
deepCheckedChildList(row){
    if(row && row.length > 0){
        row.filter(v=>{
            this.checkList.push(v.id);
            if(v.children){
                this.deepCheckedChildList(v.children);
            }
        })
    }
}

更多源码请查看:

gitee地址

github地址

父组件目录:vue-element-data\src\views\roleManage\addRole

子组件目录:vue-element-data\src\components\Page\elTableTree