背景介绍
通过表格展示树的层级,可通过对树的勾选对每一个界面的dom元素进行控制,控制程度可精确到组件/标签
图片预览
需求分析
- 根据树形结构获取层级(列数)
- 根据数据动态控制表格列数
- 格式化表格内容
- 将单元格内容(扁平化)转为结构化数据
- 勾选/取消勾选时关联相关层级
树形结构设置层级
层级部分数据如下图所示
设置第一层
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);
}
})
}
}
更多源码请查看:
父组件目录:vue-element-data\src\views\roleManage\addRole
子组件目录:vue-element-data\src\components\Page\elTableTree