0


element UI table横向树结合checkbox进行多选,实现各个节点的[全选,半选,不选]状态附带模拟数据

element UI table横向树结合checkbox进行多选,实现各个节点的[全选,半选,不选]状态,包含模拟数据

思路:

步骤一、后端返回tree格式数据,先结合element-ui的table的数据格式要求,将tree转换成table数据,进行行列的合并。
步骤二、拿到数据,递归遍历后将选中数据的id保存,进行回显操作。
步骤三、将每个checkbox进行绑定方法,此方法将作为分叉,如果当前checkbox属于父亲节点,判断当前的选中状态进行勾选,当前节点父亲节点,祖父节点和下级孩子节点进行相应的选中和状态修改,如果当前节点是最底层节点,则只需要选中上级及其上上级的节点和判断上级及上上级的状态和选中状态。重点:根据当前节点id,当前节点父节点id,子节点id,根据选中id存放的数组判树中checkbox的选中状态【半选,全选,不选】
步骤四、勾选后,调用 fatherSelectedState(i) 和 this.sonSelectedState(i) 设置当前节点下父节点,祖父节点,子节点,孙子节点的选中状态,重新刷新table树数据

elemnt 横向树,角色授权,全选半选状态

table所需要的数据格式

{id:"platform-1",name:"基础信息模块1","menuType":"0",children:[{id:"1-1",name:"用户模块权限1-1",menuType:"1",children:[{id:"1-1-1",name:"用户管理1-1-1",menuType:"2",children:[{id:"1-1-1-1",name:"组织树管理1-1-1-1",menuType:"3",children:[{id:"1-1-1-1-1",name:"新增组织树1-1-1-1-1",menuType:"4",checkFlag:true,},{id:"1-1-1-1-2",name:"编辑组织树信息1-1-1-1-2",menuType:"4",},{id:"1-1-1-1-3",name:"删除组织树1-1-1-1-3",menuType:"4",}]},{id:"1-1-1-2",name:"用户管理1-1-1-2",menuType:"3",children:[{id:"1-1-1-2-1",name:"新增组织树1-1-1-2-1",menuType:"4",},{id:"1-1-1-2-2",name:"编辑组织树信息1-1-1-2-2",menuType:"4",},{id:"1-1-1-2-3",name:"删除组织树1-1-1-2-3",menuType:"4",}]}]},{id:"1-1-2",name:"角色权限管理1-1-2",menuType:"2",children:[{id:"1-1-2-1",name:"角色权限管理1-1-2-1",menuType:"3",children:[{id:"1-1-2-1-1",name:"角色权限管理1-1-2-1-1",menuType:"4",},{id:"1-1-2-1-2",name:"角色权限管理1-1-2-1-2",menuType:"4",},{id:"1-1-2-1-3",name:"角色权限管理1-1-2-1-3",menuType:"4",}]},],}]},{id:"1-2",name:"用户模块权限1-2",menuType:"1",children:[{id:"1-2-1",name:"用户管理1-2-1",menuType:"2",children:[{id:"1-2-1-1",name:"组织树管理1-2-1-1",menuType:"3",children:[{id:"1-2-1-1-1",name:"新增组织树2",menuType:"4",},{id:"1-2-1-1-2",name:"编辑组织树信息2",menuType:"4",},{id:"1-2-1-1-3",name:"删除组织树2",menuType:"4",}]},{id:"1-2-1-2",name:"用户管理1-2-1-2",menuType:"3",children:[{id:"1-2-1-2-1",name:"新增组织树2",menuType:"4",},{id:"1-2-1-2-2",name:"编辑组织树信息2",menuType:"4",},{id:"1-2-1-2-3",name:"删除组织树2",menuType:"4",}]}]},{id:"1-2-2",name:"角色权限管理1-2-2",menuType:"2",children:[{id:"1-2-2-1",name:"角色权限管理",menuType:"3",children:[{id:"1-2-2-1-1",name:"角色权限管理",menuType:"4",},{id:"1-2-2-1-2",name:"角色权限管理",menuType:"4",},{id:"1-2-2-1-3",name:"角色权限管理",menuType:"4",}]},],}]}]},{id:"platform-2",name:"基础信息模块2",menuType:"0",children:[{id:"2-1",name:"用户模块权限2-1",menuType:"1",children:[{id:"2-1-1",name:"用户管理1",menuType:"2",children:[{id:"2-1-1-1",name:"组织树管理2AAA",menuType:"3",children:[{id:"2-1-1-1-1",name:"新增组织树2",menuType:"4",},{id:"2-1-1-1-2",name:"编辑组织树信息2",menuType:"4",},{id:"2-1-1-1-3",name:"删除组织树2",menuType:"4",}]},{id:"2-1-1-2A",name:"用户管理3",menuType:"4",children:[]},{id:"2-1-1-2B",name:"用户管理3",menuType:"4",children:[]},{id:"2-1-1-2C",name:"用户管理3",menuType:"4",children:[]},{id:"2-1-1-2D",name:"用户管理3",menuType:"4",children:[]}]},{id:"2-1-2",name:"角色权限管理2-1-2",menuType:"2",children:[{id:"2-1-2-1",menuType:"3",name:"角色权限管理2",children:[{id:"2-1-2-1-1",name:"角色权限管理2",menuType:"4",},{id:"2-1-2-1-2",name:"角色权限管理2",menuType:"4",},{id:"2-1-2-1-3",name:"角色权限管理2aaaa",menuType:"4",}]},],}]}]}

其中“menuType”代表着当前树的各个层级,最多四层,如图所示,功能层是最后两层数据的信息,所需需要将最后两层的属性“children”改为“functionChildren”,并删除children

processingTreeData(tree){//遍历树  获取id数组for(let i=0;i<tree.length;i++){//功能层和其他的children区分开来,使用functionChidlren来替代children,注意:删除childrenif(tree[i].menuType==="2"){
                    tree[i].functionChildren = tree[i].children
                    delete tree[i].children;}if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.processingTreeData(tree[i].children);}}return},

递归调用,拿到选中数据

开始拿到默认选中的数据,我的当前需求为【倒数第二层不做提交】,所以我要拿到倒数第二层的数据,提交时进行剔除
//拿到默认选中,和倒数第二层数据

processingTreeDataA(tree){//遍历树  获取id数组for(let i=0;i<tree.length;i++){//根据需求提交的时候去除第一层和倒数第二层的idif(tree[i].menuType==="3"|| tree[i].menuType==="0"){this.treeModelIds.push(tree[i].id)}//树中根据checkFlag来判断当前是否选中if(tree[i].checkFlag===true){this.treeSelectIds.push(tree[i].id)}if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.processingTreeDataA(tree[i].children);}}return},

功能权限树默认选中

//功能权限默认选中treeSekectDefault(){this.treeSelectIds.forEach(item=>{let node =this.searchTree(this.treeData,item)this.fatherSelectedState(node)this.sonSelectedState(node)})},

判断状态的主要方法[根据每个节点,判断当前节点的选中状态]

// 判断一个数组中是否包含另一个数组中的任意值(false不包含,true包含)isInclude(data){let found =falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])>-1){
                    found =truebreak}}return found
        },// 判断一个数组中是否全部在另一个数组中(true不全部包含) isIncludeArr(data){// let found = falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])===-1){returntrue}}returnfalse},//根据id找到节点searchTree(nodes, searchKey){for(let i =0; i < nodes.length; i++){if(nodes[i].id === searchKey){return nodes[i]}else{if(nodes[i].children && nodes[i].children.length >0){let res =this.searchTree(nodes[i].children, searchKey);if(res){return res
                      }}elseif(nodes[i].functionChildren && nodes[i].functionChildren.length >0){let res =this.searchTree(nodes[i].functionChildren, searchKey);if(res){return res
                      }}}}returnnull},//找到当前节点的所有父节点  data:要遍历的数据, target:查找目标, result用于装查找结果的数组findNodeAndParentsById(tree, id, parents =[]){for(const node of tree){if(node.id === id){return[...parents, node.id];}if(node.children){const result =this.findNodeAndParentsById(node.children, id,[...parents,node.id,]);if(result){return result;}}elseif(node.functionChildren){const result =this.findNodeAndParentsById(node.functionChildren, id,[...parents,node.id,]);if(result){return result;}}}returnnull;},//遍历当前节点下的idgetAllIds(tree, result){//遍历树  获取id数组for(let i=0;i<tree.length;i++){
                result.push(tree[i].id)if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.getAllIds(tree[i].children, result);}elseif(typeof(tree[i].functionChildren)!=="undefined"&& tree[i].functionChildren!==null&& tree[i].functionChildren.length>0){this.getAllIds(tree[i].functionChildren, result);}}return result;},//断一个数组中是否包含另一个数组中的任意值(false不包含,true包含)isInclude(data){let found =falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])>-1){
                    found =truebreak}}return found
        },// 判断一个数组中是否全部在另一个数组中(true不全部包含)isIncludeArr(data){// let found = falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])===-1){returnfalse}}returntrue},

重点方法!!![checkbox 的选中方法],一开始checkbox进行修改后,数据改变但是table中的视图并未改变,

解决方法1:当选中时候,处理数据,从新刷新表格和数据,使用table中的:key=“itemKey”,itemKey:Math.random(),来进行刷新表格,但是每次刷新都会回滚到最顶层,解决每次刷新滚动回到顶部问题,使用了refreshTable方法,此方法可以刷新列表后回滚到上一次选中的位置,但是频繁出现闪屏问题,弃用
解决方法2:将el-checkbox中绑定key,惊讶的发现,数据变化了视图跟着变化!!!

果断使用方法二
el-table中el-checkbox绑定数据改变了,视图未发生变化解决方法
![](https://img-blog.csdnimg.cn/219e14289dcb4a0fbeb1cf16e9c0189c.png

checkboxChange(e,i){this.$nextTick(()=>{if((typeof(i.children)!=="undefined"&& i.children.length>0)||(typeof(i.functionChildren)!=="undefined"&& i.functionChildren.length>0)){//如果当前节点为父节点this.$nextTick(()=>{if((i.checked===false&& i.indeterminate===false)||(i.checked===true&& i.indeterminate===true)){//未选中:如果当前父节点未选中,则选中所有子节点let cruuentNode =this.searchTree(this.treeData,i.id)let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])let temIdsArr =this.getAllIds([cruuentNode],[])for(let i=0;i<fatherId.length;i++){if(this.treeSelectIds.indexOf(fatherId[i])===-1){this.treeSelectIds.push(fatherId[i])let cruuentNodeB =this.searchTree(this.treeData,fatherId[i])
                            cruuentNodeB.checked =true}}for(let i=0;i<temIdsArr.length;i++){if(this.treeSelectIds.indexOf(temIdsArr[i])===-1){this.treeSelectIds.push(temIdsArr[i])let cruuentNodeA =this.searchTree(this.treeData,temIdsArr[i])
                            cruuentNodeA.checked =true}}this.fatherSelectedState(i)this.sonSelectedState(i)}elseif(i.checked===true&& i.indeterminate===false){//全选:如果当前是全选状态,点击后子节点全部去除let temIdsArr =this.getAllIds([i],[])//获取当前节点下的所有节点id              for(let i=0;i<temIdsArr.length;i++){this.treeSelectIds.splice(this.treeSelectIds.indexOf(temIdsArr[i]),1)}let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])//拿到当前节点的所有父节点的idfor(let a=fatherId.length-1;a>=0;a--){//从叶子节点开始遍历到最顶层let cruuentNode =this.searchTree(this.treeData,fatherId[a])//获取到父节点的内容let temIdsArr =this.getAllIds([cruuentNode],[])//获取当前父节点下的所有子节点idlet quchuFistId = temIdsArr.filter((element, index)=> index >0)//剔除当前父节点自己本身的节点idif(this.isInclude(quchuFistId)===false&&this.treeSelectIds.indexOf(fatherId[a])>-1){//如果当前节点的子节点的所有id不在treeSelectIds中,并且当前父节点所属子节点有任意值存在,则剔除this.treeSelectIds.splice(this.treeSelectIds.indexOf(fatherId[a]),1)}}this.fatherSelectedState(i)this.sonSelectedState(i)}})}else{//如果当前节点不是父节点if(e){//当前节点选中状态//  //根据ID获取所有 父节点,遍历父节点,编辑节点数据,如果treeSelectIds里面存在则不新增,如果不存在则新增this.findNodeAndParentsById(this.treeData,i.id,[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)
                        cruuentNode.checked =true// 如果存在id则不新增if(this.treeSelectIds.indexOf(cruuentNode.id)===-1){this.treeSelectIds.push(element)}// this.searchTree(this.treeData,element)  //               });}else{//当前节点未选中let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])//获取所有父亲节点idlet findNodeById =this.findNodeAndParentsById(this.treeData,i.id,[]).filter((element, index)=> index >0)//获取父节点id不包含本节点idfor(let i=fatherId.length-1;i>=0;i--){//从底层节点开始遍历到顶层节点let cruuentNode =this.searchTree(this.treeData,fatherId[i])//根据父节点id找到该节点,拿到遍历的父节点let temIdsArr =this.getAllIds([cruuentNode],[])//获取当前选中节点父亲节点下面的所有idlet quchuFistId = temIdsArr.filter((element, index)=> index >0)//去除当前节点父节点下的所有id,并删除父节点本身idif(this.isInclude(quchuFistId)===false){// 判断父节点在treeSelectIds上的选中状态,如果一个都不在treeSelectIds里面,则去除当前节点的idthis.treeSelectIds.splice(this.treeSelectIds.indexOf(temIdsArr[0]),1)}}}}//获取当前节点下的所有idthis.fatherSelectedState(i)//设置该节点在父节点的选中状态 this.sonSelectedState(i)//设置该节点下所有父节点的所有选中状态this.$nextTick(()=>{this.treeToTableData()//重新编辑table树this.refreshTable()//无感刷新table树结构,滚动记录 })})this.$forceUpdate()},//设置该节点下所有子节点的所有选中状态sonSelectedState(i){this.getAllIds([i],[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)let a =this.getAllIds([cruuentNode],[]).filter((element, index)=> index >0)if(this.isIncludeArr(this.getAllIds([cruuentNode],[]))&&this.isInclude(this.getAllIds([cruuentNode],[]))){//全选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =true}elseif(this.isIncludeArr(this.getAllIds([cruuentNode],[]))===false&&this.isInclude(this.getAllIds([cruuentNode],[]))===true){//半选
                    cruuentNode.indeterminate =true
                    cruuentNode.checked =true}elseif(this.isIncludeArr(this.getAllIds([cruuentNode],[]))===false&&this.isInclude(this.getAllIds([cruuentNode],[]))===false){//不选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =false}});},//设置该节点在父节点的选中状态fatherSelectedState(i){this.findNodeAndParentsById(this.treeData,i.id,[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)let a =this.getAllIds([cruuentNode],[]).filter((element, index)=> index >0)if(this.isIncludeArr(a)&&this.isInclude(a)){//全选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =true}elseif(this.isIncludeArr(a)===false&&this.isInclude(a)===true){//半选
                    cruuentNode.indeterminate =true
                    cruuentNode.checked =true}elseif(this.isIncludeArr(a)===false&&this.isInclude(a)===false){//不选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =false}});},

将tree树状格式转换成el-table表格可识别格式,并进行单元格合并

  1. 将tree数据转换成二维表格数据
  2. 合并行或列的计算方法
  3. 表格单元格合并-----行
//tree数据处理treeToTableData(){//将树状结构格式转换成二维数组表格形式let ewArr =this.parseTreeToRow(this.treeData);let tableData =[];
            ewArr.map((item,index)=>{if(item.length===2){
                    item.push({label:item[1].label+item.length,isChecked:false,})}elseif(item.length===1){
                    item.push({label:item[0].label+"1",isChecked:false,})
                    item.push({label:item[0].label+"2",isChecked:false,})}let obj ={};
                item.map((itemc, indexb)=>{// typeof(itemc.functionChildren)!=="undefined"?itemc.functionChildren:null
                    obj["index"+(indexb +1)]={id: itemc.id,label: itemc.label,functionChildren:(itemc.functionChildren !==null)?itemc.functionChildren:[],children:(itemc.children !==null)?itemc.children:[],checked:(typeof itemc.checked !=="undefined")?itemc.checked:false,isChecked:itemc.isChecked===false?itemc.isChecked:true,indeterminate:(typeof itemc.indeterminate !=="undefined")?itemc.indeterminate:false};if(typeof itemc.children !=="undefined"){
                        obj.children ={data: itemc.children };}});
                tableData.push(obj);});this.tableData = tableData;},/**
         * 递归-----将树结构数据格式,转化为,二维数组 表格形式
         * @param node 树的源数据
         * @param data 树转化为二维数组的数据
         * @param row 临时存储数据
         * @returns {*[]}
         */parseTreeToRow(node, data =[], row =[]){            
            node.map((item)=>{let obj ={id: item.id,label:item.name,functionChildren:typeof(item.functionChildren)!=="undefined"?item.functionChildren:null,children:(item.children !==null)?item.children:null,checked:(typeof item.checked !=="undefined")?item.checked:false,indeterminate:(typeof item.indeterminate !=="undefined")?item.indeterminate:false};if(typeof item.children !=="undefined"){
                    obj.children = item.children.length >0? item.children :[];}if(item.children && item.children.length !=0){this.parseTreeToRow(item.children, data,[...row, obj]);}else{
                    data.push([...row, obj]);}});return data;},/**
         * 合并行或列的计算方法
         */tableSpanMethod({ row, column, rowIndex, columnIndex }){return{rowspan:
                columnIndex <3?this.mergeRows(
                        row[column.property],this.tableData,
                        rowIndex,
                        column.property
                    ):1,colspan:1,};},/**
         * 表格单元格合并-----行
         * @param {Object} value      当前单元格的值
         * @param {Object} data       当前表格所有数据
         * @param {Object} index      当前单元格的值所在 行 索引
         * @param {Object} property   当前列的property
         * @returns {number}          待合并单元格数量
         */mergeRows(value, data, index, property){// 判断 当前行的该列数据 与 上一行的该列数据 是否相等if(index !==0&& value.label === data[index -1][property].label){// 返回 0 使表格被跨 行 的那个单元格不会渲染return0;}// 判断 当前行的该列数据 与 下一行的该列数据 是否相等  let rowSpan =1;for(let i = index +1; i < data.length; i++){if(value.label !== data[i][property].label){break;}
                rowSpan++;}return rowSpan;},

完整代码粘贴,附带模拟数据:

<template><div><el-drawer class="el-drawer-role" title="我是标题":visible.sync="drawer" size="70%":with-header="false":before-close="drawerClose"><el-tabs style="padding: 20px;"  v-model="activeName" @tab-click="handleClick"><el-tab-pane label="应用权限" name="first"><el-table ref="multipleTable"border:data="appTableData" tooltip-effect="dark" style="width: 100%"
                         @selection-change="handleSelectionChange"><el-table-column type="selection" align="center" width="55"></el-table-column><el-table-column prop="key" label="应用编码" align="center"  width="120"></el-table-column><el-table-column prop="name" label="应用名称" align="center"  show-overflow-tooltip></el-table-column></el-table></el-tab-pane><el-tab-pane label="功能权限" name="second"><el-input
                        v-model="searchContent"
                        placeholder="搜索"
                        clearable
                        size="small"
                        prefix-icon="el-icon-search"
                        style="margin-bottom: 20px"/><el-table style="margin-bottom: 70px;":key="itemKey":height="contentHeight"class="ganteTable" ref="table":span-method="tableSpanMethod":data="tableData" border align="center" size="mini"><el-table-column align="center" prop="index1" label="应用" width="200px"><template slot-scope="scope">{{ scope.row.index1.checked }}<el-checkbox  @change="checkboxChange($event,scope.row.index1)":key="scope.row.index1.checked+scope.row.index1.indeterminate+''":indeterminate="scope.row.index1.indeterminate":checked="scope.row.index1.checked":label="scope.row.index1.label"></el-checkbox><br /></template></el-table-column><el-table-column align="center" prop="index2" label="模块" width="200px"><template slot-scope="scope">{{ scope.row.index2.checked }}<el-checkbox v-if="scope.row.index2.isChecked":key="scope.row.index2.checked+scope.row.index2.indeterminate+''" @change="checkboxChange($event,scope.row.index2)":indeterminate="scope.row.index2.indeterminate":checked="scope.row.index2.checked":label="scope.row.index2.label"></el-checkbox><br /></template></el-table-column><el-table-column align="center" prop="index3" label="界面"  width="200px"><template slot-scope="scope">{{ scope.row.index3.checked }}<el-checkbox v-if="scope.row.index3.isChecked":key="scope.row.index3.checked+scope.row.index3.indeterminate+''" @change="checkboxChange($event,scope.row.index3)":indeterminate="scope.row.index3.indeterminate":checked="scope.row.index3.checked":label="scope.row.index3.label"></el-checkbox><br /></template></el-table-column><el-table-column prop="children" label="功能"><template slot-scope="scope"><span  v-for="item in scope.row.index3.functionChildren":key="item.id"><div style="margin: 7px;" v-if="item.menuType==='3'">{{ item.name }}<br /><span style="margin: 7px;margin-left:10px;" v-for="item2 in item.children":key="item2.id"><el-checkbox :checked="item2.checked":indeterminate="item2.indeterminate":key="item2.checked+item2.indeterminate+''" @change="checkboxChange($event,item2)"><span v-if="item2.name.indexOf(searchContent)>-1"><span style="color: #f50">{{ searchContent }}</span>{{ item2.name.substr(item2.name.indexOf(searchContent)+ searchContent.length)}}</span><span v-else>{{ item2.name }}</span></el-checkbox></span></div><span v-if="item.menuType==='4'" style="margin: 7px;margin-left:10px;"><el-checkbox @change="checkboxChange($event,item)":key="item.checked+item.indeterminate+''":indeterminate="item.indeterminate":checked="item.checked":label="item.name"></el-checkbox></span></span></template></el-table-column></el-table></el-tab-pane></el-tabs><div class="demo-drawer__footer" style="position: fixed;bottom: 20px;right: 20px; background: white; "><el-button @click="drawerClose">取 消</el-button><el-button type="primary" @click="submitRole()">确定</el-button></div></el-drawer></div></template><script>import{ platformGetList,getPlatFormByRoleId,getRolePermissionTreeList,assignRolePermission }from"@/api/userInfo/role"exportdefault{data(){return{temObj:{},contentHeight:'0px',searchContent:"",defaultTreeSelect:[],appTableDefaultSelect:[],appTableData:[],multipleSelection:[],checkAll:true,tableData:[],treeSelectIds:[],itemKey:Math.random(),drawer:false,//抽屉打开关闭状态activeName:"first",//当前tab激活的状态treeModelIds:[],//模块ids不需要传递,和第一层次ID不需要传递treeData:[// {//     id:"platform-1",//     name:"基础信息模块1",//     "menuType": "0",//     children:[//         {//             id:"1-1",//             name:"用户模块权限1-1",//             menuType: "1",//             children:[//                 {//                     id:"1-1-1",//                     name:"用户管理1-1-1",//                     menuType: "2",//                     children:[//                         {//                             id:"1-1-1-1",//                             name:"组织树管理1-1-1-1",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-1-1-1-1",//                                     name:"新增组织树1-1-1-1-1",//                                     menuType: "4",//                                     checkFlag:true,//                                 },//                                 {//                                     id:"1-1-1-1-2",//                                     name:"编辑组织树信息1-1-1-1-2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-1-1-1-3",//                                     name:"删除组织树1-1-1-1-3",//                                     menuType: "4",//                                 }//                             ]//                         },//                         {//                             id:"1-1-1-2",//                             name:"用户管理1-1-1-2",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-1-1-2-1",//                                     name:"新增组织树1-1-1-2-1",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-1-1-2-2",//                                     name:"编辑组织树信息1-1-1-2-2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-1-1-2-3",//                                     name:"删除组织树1-1-1-2-3",//                                     menuType: "4",//                                 }//                             ]//                         }//                     ]//                 },//                 {//                     id:"1-1-2",//                     name:"角色权限管理1-1-2",//                     menuType: "2",//                     children:[//                         {//                             id:"1-1-2-1",//                             name:"角色权限管理1-1-2-1",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-1-2-1-1",//                                     name:"角色权限管理1-1-2-1-1",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-1-2-1-2",//                                     name:"角色权限管理1-1-2-1-2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-1-2-1-3",//                                     name:"角色权限管理1-1-2-1-3",//                                     menuType: "4",//                                 }//                             ]//                         },//                     ],//                 }//             ]//         },//         {//             id:"1-2",//             name:"用户模块权限1-2", //             menuType: "1", //              children:[//                 {//                     id:"1-2-1",//                     name:"用户管理1-2-1",//                     menuType: "2", //                     children:[//                         {//                             id:"1-2-1-1",//                             name:"组织树管理1-2-1-1",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-2-1-1-1",//                                     name:"新增组织树2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-1-1-2",//                                     name:"编辑组织树信息2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-1-1-3",//                                     name:"删除组织树2",//                                     menuType: "4",//                                 }//                             ]//                         },//                         {//                             id:"1-2-1-2",//                             name:"用户管理1-2-1-2",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-2-1-2-1",//                                     name:"新增组织树2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-1-2-2",//                                     name:"编辑组织树信息2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-1-2-3",//                                     name:"删除组织树2",//                                     menuType: "4",//                                 }//                             ]//                         }//                     ]//                 },//                 {//                     id:"1-2-2",//                     name:"角色权限管理1-2-2",//                     menuType: "2",//                     children:[//                         {//                             id:"1-2-2-1",//                             name:"角色权限管理",//                             menuType: "3",//                             children:[//                                 {//                                     id:"1-2-2-1-1",//                                     name:"角色权限管理",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-2-1-2",//                                     name:"角色权限管理",//                                     menuType: "4",//                                 },//                                 {//                                     id:"1-2-2-1-3",//                                     name:"角色权限管理",//                                     menuType: "4",//                                 }//                             ]//                         },//                     ],//                 }//             ]//         }//     ]// },// {//     id:"platform-2",//     name:"基础信息模块2",//     menuType: "0",//     children:[//         {//             id:"2-1",//             name:"用户模块权限2-1",//             menuType: "1",//             children:[//                 {//                     id:"2-1-1",//                     name:"用户管理1",//                     menuType: "2",//                     children:[//                         {//                             id:"2-1-1-1",//                             name:"组织树管理2AAA",//                             menuType: "3",//                             children:[//                                 {//                                     id:"2-1-1-1-1",//                                     name:"新增组织树2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"2-1-1-1-2",//                                     name:"编辑组织树信息2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"2-1-1-1-3",//                                     name:"删除组织树2",//                                     menuType: "4",//                                 }//                             ]//                         },//                         {//                             id:"2-1-1-2A",//                             name:"用户管理3",//                             menuType: "4",//                             children:[]//                         },//                         {//                             id:"2-1-1-2B",//                             name:"用户管理3",//                             menuType: "4",//                             children:[]//                         },//                         {//                             id:"2-1-1-2C",//                             name:"用户管理3",//                             menuType: "4",//                             children:[]//                         },{//                             id:"2-1-1-2D",//                             name:"用户管理3",//                             menuType: "4",//                             children:[//                             ]//                         }//                     ]//                 },//                 {//                     id:"2-1-2",//                     name:"角色权限管理2-1-2",//                     menuType: "2",//                     children:[//                         {//                             id:"2-1-2-1",//                             menuType: "3",//                             name:"角色权限管理2",//                             children:[//                                 {//                                     id:"2-1-2-1-1",//                                     name:"角色权限管理2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"2-1-2-1-2",//                                     name:"角色权限管理2",//                                     menuType: "4",//                                 },//                                 {//                                     id:"2-1-2-1-3",//                                     name:"角色权限管理2aaaa",//                                     menuType: "4",//                                 }//                             ]//                         },//                     ],//                 }//             ]//         }//     ]// }]}},created(){},mounted(){},methods:{//获取应用平台权限platformGetList(roleId){this.multipleSelection =[]getPlatFormByRoleId({roleId:roleId}).then(res=>{this.appTableData = res.data
                this.$nextTick(()=>{
                    console.log("this.appTableData",this.appTableData)// this.defaultSelect()this.appTableData.forEach(item=>{if(item.selFlag){//再遍历数组,将数据放入方法中  this.$refs.multipleTable.toggleRowSelection(item,true)}})})})},//最后一层加上functionChildrenprocessingTreeData(tree){//遍历树  获取id数组for(let i=0;i<tree.length;i++){//功能层和其他的children区分开来,使用functionChidlren来替代children,注意:删除childrenif(tree[i].menuType==="2"){
                    tree[i].functionChildren = tree[i].children
                    delete tree[i].children;}if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.processingTreeData(tree[i].children);}}return},//拿到默认选中,和倒数第二层数据processingTreeDataA(tree){//遍历树  获取id数组for(let i=0;i<tree.length;i++){//根据需求提交的时候去除第一层和倒数第二层的idif(tree[i].menuType==="3"|| tree[i].menuType==="0"){this.treeModelIds.push(tree[i].id)}//树中根据checkFlag来判断当前是否选中if(tree[i].checkFlag===true){this.treeSelectIds.push(tree[i].id)}if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.processingTreeDataA(tree[i].children);}}return},//菜单层选中状态processingTreeDataB(tree){//遍历树  获取id数组for(let i=0;i<tree.length;i++){//判断菜单那一成是否需要选中if(tree[i].menuType==="3"){//遍历菜单层,判断菜单层下的所有按钮权限只要有一个选中,根据这一个选中判断菜单层的选中状态for(let j=0;j<tree[i].children.length;j++){//如果菜单下的按钮权限有一个包含在treeSelectIds中,则当前菜单被选中if(this.treeSelectIds.indexOf(tree[i].children[j].id)!==-1){//按钮id存在,并且treeSelectIds中没有当前id,则push操作if(this.treeSelectIds.indexOf(tree[i].id)===-1){//则当前菜单被选中后结束当前循环,拿到id,根据id的父节点,子节点判定当前菜单的选中状态this.treeSelectIds.push(tree[i].id)break}}}}if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.processingTreeDataB(tree[i].children);}}return},//提交submitRole(){//去除第一层和倒数第二层的idlet newArr =this.treeSelectIds .filter((x)=>!this.treeModelIds.some((item)=> x === item));let temObj ={}
            temObj.departId =this.temObj.departId
            temObj.roleId =this.temObj.roleId
            temObj.permissionIdList = newArr
            assignRolePermission(temObj).then(res=>{this.$message({message:'角色权限授权成功',type:'success'});})},//应用列表默认多选defaultSelect(){// //创建一个空数组用来存放默认数据// let list = []// //遍历表格的数据,再遍历需要在表格中反显的数据,两者的id一致// this.appTableData.forEach((item) => {//     this.appTableDefaultSelect.forEach(val => {//         if (val=== item.id) {//             // 把判断出来的默认表格数据push到创建的数组中//             list.push(item)//         }//     })// })// if (list) {//     //再遍历数组,将数据放入方法中  //     list.forEach((row) => {//         this.$refs.multipleTable.toggleRowSelection(row,true)//     })// }},//多选handleSelectionChange(val){this.multipleSelection =[]
            val.forEach(item=>{this.multipleSelection.push(item.id);})//如果有选中则请求选中的所属树if(this.multipleSelection.length>0){this.temObj.platformIdList =this.multipleSelection
                this.treeModelIds =[]this.treeSelectIds =[]getRolePermissionTreeList(this.temObj).then(res=>{this.treeData = res.data
                    this.refreshTable()//刷新tree表this.processingTreeDataA(this.treeData)//拿到树中的已选中的id和第一层id和倒数第二次idthis.processingTreeDataB(this.treeData)//判断倒数第三层的选中状态,后端返回第三层没有返回选中状态,this.processingTreeData(this.treeData)//给最后一层加上functionChidrenthis.treeSekectDefault()//功能权限树默认选中this.treeToTableData()//将功能权限树转换成表格形式并合并单元格 this.contentHeight = document.getElementsByClassName("el-drawer__body")[0].clientHeight-220+'px'})}else{this.temObj.platformIdList =[]this.treeData =[]}},//功能权限默认选中treeSekectDefault(){this.treeSelectIds.forEach(item=>{let node =this.searchTree(this.treeData,item)this.fatherSelectedState(node)this.sonSelectedState(node)})},// 判断一个数组中是否包含另一个数组中的任意值(false不包含,true包含)isInclude(data){let found =falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])>-1){
                    found =truebreak}}return found
        },// 判断一个数组中是否全部在另一个数组中(true不全部包含) isIncludeArr(data){// let found = falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])===-1){returntrue}}returnfalse},//判断当前节点的选中状态,0未选中,1选中,2半选checkboxStatus(){this.searchTree(this.treeData,i.id)},//根据id找到节点searchTree(nodes, searchKey){for(let i =0; i < nodes.length; i++){if(nodes[i].id === searchKey){return nodes[i]}else{if(nodes[i].children && nodes[i].children.length >0){let res =this.searchTree(nodes[i].children, searchKey);if(res){return res
                        }}elseif(nodes[i].functionChildren && nodes[i].functionChildren.length >0){let res =this.searchTree(nodes[i].functionChildren, searchKey);if(res){return res
                        }}}}returnnull},//找到当前节点的所有父节点  data:要遍历的数据, target:查找目标, result用于装查找结果的数组findNodeAndParentsById(tree, id, parents =[]){for(const node of tree){if(node.id === id){return[...parents, node.id];}if(node.children){const result =this.findNodeAndParentsById(node.children, id,[...parents,node.id,]);if(result){return result;}}elseif(node.functionChildren){const result =this.findNodeAndParentsById(node.functionChildren, id,[...parents,node.id,]);if(result){return result;}}}returnnull;},//遍历当前节点下的idgetAllIds(tree, result){//遍历树  获取id数组for(let i=0;i<tree.length;i++){
                result.push(tree[i].id)if(typeof(tree[i].children)!=="undefined"&& tree[i].children!==null&& tree[i].children.length>0){this.getAllIds(tree[i].children, result);}elseif(typeof(tree[i].functionChildren)!=="undefined"&& tree[i].functionChildren!==null&& tree[i].functionChildren.length>0){this.getAllIds(tree[i].functionChildren, result);}}return result;},//断一个数组中是否包含另一个数组中的任意值(false不包含,true包含)isInclude(data){let found =falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])>-1){
                    found =truebreak}}return found
        },// 判断一个数组中是否全部在另一个数组中(true不全部包含)isIncludeArr(data){// let found = falsefor(let i =0; i < data.length; i++){if(this.treeSelectIds.indexOf(data[i])===-1){returnfalse}}returntrue},//选中checkboxChange(e,i){this.$nextTick(()=>{if((typeof(i.children)!=="undefined"&& i.children.length>0)||(typeof(i.functionChildren)!=="undefined"&& i.functionChildren.length>0)){//如果当前节点为父节点this.$nextTick(()=>{if((i.checked===false&& i.indeterminate===false)||(i.checked===true&& i.indeterminate===true)){//未选中:如果当前父节点未选中,则选中所有子节点let cruuentNode =this.searchTree(this.treeData,i.id)let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])let temIdsArr =this.getAllIds([cruuentNode],[])for(let i=0;i<fatherId.length;i++){if(this.treeSelectIds.indexOf(fatherId[i])===-1){this.treeSelectIds.push(fatherId[i])let cruuentNodeB =this.searchTree(this.treeData,fatherId[i])
                            cruuentNodeB.checked =true}}for(let i=0;i<temIdsArr.length;i++){if(this.treeSelectIds.indexOf(temIdsArr[i])===-1){this.treeSelectIds.push(temIdsArr[i])let cruuentNodeA =this.searchTree(this.treeData,temIdsArr[i])
                            cruuentNodeA.checked =true}}this.fatherSelectedState(i)this.sonSelectedState(i)}elseif(i.checked===true&& i.indeterminate===false){//全选:如果当前是全选状态,点击后子节点全部去除let temIdsArr =this.getAllIds([i],[])//获取当前节点下的所有节点id              for(let i=0;i<temIdsArr.length;i++){this.treeSelectIds.splice(this.treeSelectIds.indexOf(temIdsArr[i]),1)}let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])//拿到当前节点的所有父节点的idfor(let a=fatherId.length-1;a>=0;a--){//从叶子节点开始遍历到最顶层let cruuentNode =this.searchTree(this.treeData,fatherId[a])//获取到父节点的内容let temIdsArr =this.getAllIds([cruuentNode],[])//获取当前父节点下的所有子节点idlet quchuFistId = temIdsArr.filter((element, index)=> index >0)//剔除当前父节点自己本身的节点idif(this.isInclude(quchuFistId)===false&&this.treeSelectIds.indexOf(fatherId[a])>-1){//如果当前节点的子节点的所有id不在treeSelectIds中,并且当前父节点所属子节点有任意值存在,则剔除this.treeSelectIds.splice(this.treeSelectIds.indexOf(fatherId[a]),1)}}this.fatherSelectedState(i)this.sonSelectedState(i)}})}else{//如果当前节点不是父节点if(e){//当前节点选中状态//  //根据ID获取所有 父节点,遍历父节点,编辑节点数据,如果treeSelectIds里面存在则不新增,如果不存在则新增this.findNodeAndParentsById(this.treeData,i.id,[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)
                        cruuentNode.checked =true// 如果存在id则不新增if(this.treeSelectIds.indexOf(cruuentNode.id)===-1){this.treeSelectIds.push(element)}// this.searchTree(this.treeData,element)  //               });}else{//当前节点未选中let fatherId =this.findNodeAndParentsById(this.treeData,i.id,[])//获取所有父亲节点idlet findNodeById =this.findNodeAndParentsById(this.treeData,i.id,[]).filter((element, index)=> index >0)//获取父节点id不包含本节点idfor(let i=fatherId.length-1;i>=0;i--){//从底层节点开始遍历到顶层节点let cruuentNode =this.searchTree(this.treeData,fatherId[i])//根据父节点id找到该节点,拿到遍历的父节点let temIdsArr =this.getAllIds([cruuentNode],[])//获取当前选中节点父亲节点下面的所有idlet quchuFistId = temIdsArr.filter((element, index)=> index >0)//去除当前节点父节点下的所有id,并删除父节点本身idif(this.isInclude(quchuFistId)===false){// 判断父节点在treeSelectIds上的选中状态,如果一个都不在treeSelectIds里面,则去除当前节点的idthis.treeSelectIds.splice(this.treeSelectIds.indexOf(temIdsArr[0]),1)}}}}//获取当前节点下的所有idthis.fatherSelectedState(i)//设置该节点在父节点的选中状态 this.sonSelectedState(i)//设置该节点下所有父节点的所有选中状态this.$nextTick(()=>{this.treeToTableData()//重新编辑table树this.refreshTable()//无感刷新table树结构,滚动记录 })})this.$forceUpdate()},/**
         * 刷新table时候,无感刷新,定位到上一次选中的滚动中
        */refreshTable(){// let beforeScrollTop = this.$refs.table.$el.querySelector('div.el-table__body-wrapper').scrollTop// // this.itemKey = Math.random()// this.$forceUpdate()// this.$nextTick(()=> {//     setTimeout(() => {//         this.$refs.table.$el.querySelector('div.el-table__body-wrapper').scrollTop = beforeScrollTop//     },0)// })},//设置该节点下所有子节点的所有选中状态sonSelectedState(i){this.getAllIds([i],[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)let a =this.getAllIds([cruuentNode],[]).filter((element, index)=> index >0)if(this.isIncludeArr(this.getAllIds([cruuentNode],[]))&&this.isInclude(this.getAllIds([cruuentNode],[]))){//全选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =true}elseif(this.isIncludeArr(this.getAllIds([cruuentNode],[]))===false&&this.isInclude(this.getAllIds([cruuentNode],[]))===true){//半选
                    cruuentNode.indeterminate =true
                    cruuentNode.checked =true}elseif(this.isIncludeArr(this.getAllIds([cruuentNode],[]))===false&&this.isInclude(this.getAllIds([cruuentNode],[]))===false){//不选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =false}});},//设置该节点在父节点的选中状态fatherSelectedState(i){this.findNodeAndParentsById(this.treeData,i.id,[]).forEach(element=>{let cruuentNode =this.searchTree(this.treeData,element)let a =this.getAllIds([cruuentNode],[]).filter((element, index)=> index >0)if(this.isIncludeArr(a)&&this.isInclude(a)){//全选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =true}elseif(this.isIncludeArr(a)===false&&this.isInclude(a)===true){//半选
                    cruuentNode.indeterminate =true
                    cruuentNode.checked =true}elseif(this.isIncludeArr(a)===false&&this.isInclude(a)===false){//不选
                    cruuentNode.indeterminate =false
                    cruuentNode.checked =false}});},//tab选项卡handleClick(tab, event){},//分配权限assignPermissions(data){//获取平台列表this.platformGetList(data.roleId)this.temObj.departId = data.departId 
            this.temObj.roleId = data.roleId            
            this.drawer =true},//关闭窗口drawerClose(){this.activeName ="first"this.tableData =[]this.treeSelectIds =[]this.treeModelIds =[]this.refreshTable()this.drawer =false},//tree数据处理treeToTableData(){//将树状结构格式转换成二维数组表格形式let ewArr =this.parseTreeToRow(this.treeData);let tableData =[];
            ewArr.map((item,index)=>{if(item.length===2){
                    item.push({label:item[1].label+item.length,isChecked:false,})}elseif(item.length===1){
                    item.push({label:item[0].label+"1",isChecked:false,})
                    item.push({label:item[0].label+"2",isChecked:false,})}let obj ={};
                item.map((itemc, indexb)=>{// typeof(itemc.functionChildren)!=="undefined"?itemc.functionChildren:null
                    obj["index"+(indexb +1)]={id: itemc.id,label: itemc.label,functionChildren:(itemc.functionChildren !==null)?itemc.functionChildren:[],children:(itemc.children !==null)?itemc.children:[],checked:(typeof itemc.checked !=="undefined")?itemc.checked:false,isChecked:itemc.isChecked===false?itemc.isChecked:true,indeterminate:(typeof itemc.indeterminate !=="undefined")?itemc.indeterminate:false};if(typeof itemc.children !=="undefined"){
                        obj.children ={data: itemc.children };}});
                tableData.push(obj);});this.tableData = tableData;},/**
         * 递归-----将树结构数据格式,转化为,二维数组 表格形式
         * @param node 树的源数据
         * @param data 树转化为二维数组的数据
         * @param row 临时存储数据
         * @returns {*[]}
         */parseTreeToRow(node, data =[], row =[]){            
            node.map((item)=>{let obj ={id: item.id,label:item.name,functionChildren:typeof(item.functionChildren)!=="undefined"?item.functionChildren:null,children:(item.children !==null)?item.children:null,checked:(typeof item.checked !=="undefined")?item.checked:false,indeterminate:(typeof item.indeterminate !=="undefined")?item.indeterminate:false};if(typeof item.children !=="undefined"){
                    obj.children = item.children.length >0? item.children :[];}if(item.children && item.children.length !=0){this.parseTreeToRow(item.children, data,[...row, obj]);}else{
                    data.push([...row, obj]);}});return data;},/**
         * 合并行或列的计算方法
         */tableSpanMethod({ row, column, rowIndex, columnIndex }){return{rowspan:
                columnIndex <3?this.mergeRows(
                        row[column.property],this.tableData,
                        rowIndex,
                        column.property
                    ):1,colspan:1,};},/**
         * 表格单元格合并-----行
         * @param {Object} value      当前单元格的值
         * @param {Object} data       当前表格所有数据
         * @param {Object} index      当前单元格的值所在 行 索引
         * @param {Object} property   当前列的property
         * @returns {number}          待合并单元格数量
         */mergeRows(value, data, index, property){// 判断 当前行的该列数据 与 上一行的该列数据 是否相等if(index !==0&& value.label === data[index -1][property].label){// 返回 0 使表格被跨 行 的那个单元格不会渲染return0;}// 判断 当前行的该列数据 与 下一行的该列数据 是否相等  let rowSpan =1;for(let i = index +1; i < data.length; i++){if(value.label !== data[i][property].label){break;}
                rowSpan++;}return rowSpan;},//递归遍历树数据}}</script><style scoped>.search{color: red;}</style>

最终效果:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

标签: elementui vue.js 前端

本文转载自: https://blog.csdn.net/qq_42696432/article/details/132847579
版权归原作者 吴用_前端开发 所有, 如有侵权,请联系我们删除。

“element UI table横向树结合checkbox进行多选,实现各个节点的[全选,半选,不选]状态附带模拟数据”的评论:

还没有评论