首先看一下效果:
然后再说一下数据的格式和字段
其中IsObtain为是否选中字段,halfchecked为半选状态,permission_id为id,permission_pid为父id,其他的根据自己的业务需求来。
然后看一下层级关系
最后,废话不多说,直接上代码
其中一到三步就是对antd表格的魔改,就对应自己数据的字段改一下就ok,不用去深究。
为了方便大家看懂,代码里大量的注释,并且先看哪个方法的步骤都已标明,所以我就步赘述了,直接上完整代码:
index.tsx: 数据是自己造的
import React, { useState } from 'react'
import Child from "./Child"
// import Child1 from "./Child1"
export default function Index() {
const [data, stedata] = useState([
{
IsObtain: false,
halfchecked: false,
permission_id: "1",
permission_name: "权限1",
permission_pid: null,
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "1-1",
permission_name: "权限1-1",
permission_pid: "1",
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "1-1-1",
permission_name: "权限1-1-1",
permission_pid: "1-1",
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "1-1-1-1",
permission_name: "权限1-1-1-1",
permission_pid: "1-1-1",
childPermissions: null
},
{
IsObtain: false,
halfchecked: false,
permission_id: "1-1-1-2",
permission_name: "权限1-1-1-2",
permission_pid: "1-1-1",
childPermissions: null
}
]
},
{
IsObtain: false,
halfchecked: false,
permission_id: "1-1-2",
permission_name: "权限1-1-2",
permission_pid: "1-1",
childPermissions: null
}
]
},
{
IsObtain: false,
halfchecked: false,
permission_id: "1-2",
permission_name: "权限1-2",
permission_pid: "1",
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "1-2-1",
permission_name: "权限1-2-1",
permission_pid: "1-2",
childPermissions: null
}
]
},
],
},
{
IsObtain: false,
halfchecked: false,
permission_id: "2",
permission_name: "权限2",
permission_pid: null,
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "2-1",
permission_name: "权限2-1",
permission_pid: "2",
childPermissions: [
{
IsObtain: false,
halfchecked: false,
permission_id: "2-1-1",
permission_name: "权限2-1-1",
permission_pid: "2-1",
childPermissions: null
},
{
IsObtain: false,
halfchecked: false,
permission_id: "2-1-2",
permission_name: "权限1-1-2",
permission_pid: "2-1",
childPermissions: null
}
]
},
],
}
]);
return (
{/* */}
)
}
Child.tsx:
//@ts-nocheck
import { useEffect, useState } from "react";
import { Checkbox, Table, Button, message } from "antd";
// import { postaddpermission } from "../../../api/permissionGroup";
export default function RoleList(props) {
const [dataSource1, setdataSource] = useState()
const [columns1, setcolumns] = useState()
const [ccType, setccType] = useState(false)
const columnWidthArray = ["10%", "10%", "30%", "25%", "25%"]
//第二步,编码Data, 转成表格格式
const encodeData = (data, i = 0, addData = {}) => {
let ret = [];
// eslint-disable-next-line array-callback-return
data?.map((item) => {
let next = Object.assign({ [i]: item.permission_id }, addData);
//如果有子数据
if (item.childPermissions) {
ret.push(...encodeData(item.childPermissions, i + 1, next));
} else {
ret.push(next);
}
});
return ret;
};
//第三步,获取最深的深度以确定列数
const getMaxDepth = (data) => {
let max = 1;
data?.map((item) => {
if (item.childPermissions) {
let childDepth = getMaxDepth(item.childPermissions);
if (max < 1 + childDepth) max = 1 + childDepth;
}
});
return max;
};
//第一步,这里面就是将antd表格改成权限组选择想要的样子,并且调了一下方法
const generateData = (list) => {
//转换格式后生成的表格数据
const dataSource = encodeData(list);
//最大深度, 用于确认表格列数
const max = getMaxDepth(list);
const columns = [];
for (let i = 0; i < max; i++) {
columns.push({
key: i,
dataIndex: i,
title: i,
width: columnWidthArray[i],
render: (t, r, rowIndex) => {
const obj = {
children: t ? getCheckBox(t, list) : "",
props: {},
};
//列合并
if (r[i] === undefined) {
obj.props.colSpan = 0;
} else if (r[i + 1] === undefined && i < max - 1) {
obj.props.colSpan = max - i;
}
//行合并
if (
dataSource[rowIndex - 1] &&
dataSource[rowIndex - 1][i] === dataSource[rowIndex][i]
) {
obj.props.rowSpan = 0;
} else {
let rowSpan = 1;
for (
let j = 1;
dataSource[rowIndex + j] &&
dataSource[rowIndex + j][i] === dataSource[rowIndex][i];
j++
) {
rowSpan++;
}
obj.props.rowSpan = rowSpan;
}
return obj;
},
});
}
setdataSource(dataSource)
setcolumns(columns)
};
//第五步,利用id获取整个对象
//obj:传入的一个空对象
//id:传入的数据id
//list:整个权限的数据,是一个数组对象的格式
const mapData = (obj, id, list) => {
list.map(item => {
//如果id相等,则把整个对象赋给ogj,否则如果有子数据就递归
if (item.permission_id === id) {
obj = item
} else if (item.childPermissions) {
obj = mapData(obj, id, item.childPermissions)
}
})
//最后将对象返回
return obj
}
//第九步,半选
//list:总数据
const halfchecked = (list) => {
list.map(item => {
if (item.childPermissions) {
// 用数组的方法,有一个为true就为true,这里一定要加上|| item.halfchecked,因为如果是半选状态,它的父级也应该是半选状态,不加会导致三个层级以上出现bug
let flag = item.childPermissions.some(item => item.IsObtain || item.halfchecked)
item.halfchecked = flag
// 再递归
halfchecked(item.childPermissions)
}
})
}
//第八步,反选
//list:总数据
const reversecheck = (list) => {
list.map(item => {
if (item.childPermissions) {
// 用数组的方法,全部都为true才为true
let flag = item.childPermissions.every(item => item.IsObtain)
item.IsObtain = flag
// 再递归
reversecheck(item.childPermissions)
}
})
}
//第七步,全选
//checked:选择框状态,data:数据
const checkAllbtn = (checked, data) => {
data.map(item => {
item.IsObtain = checked
if (item.childPermissions) {
checkAllbtn(checked, item.childPermissions)
}
})
}
//第六步,点击选择框
//data:总数据,checked:选择框的状态,id:当前数据的id
const checkedItem = (data, checked, id) => {
//把传过来的数据进行遍历
return data.map(item => {
//如果id相等就把数据的IsObtain字段改成当前选择框的状态
if (item.permission_id === id) {
item.IsObtain = checked
//全选,如果有子数据就调全选的方法
if (item.childPermissions) {
checkAllbtn(checked, item.childPermissions)
}
//如果父id不会空,那就说明点击的是子选择框,就要进行反选和半选
if (item.permission_pid !== "null") {
//反选/半选
reversecheck(props.dataList)
halfchecked(props.dataList)
}
}
//递归,如果有子数据就进行递归
else if (item.childPermissions) {
checkedItem(item.childPermissions, checked, id)
}
return item
})
}
//第四步,渲染选择框
//t:当前数据的id, data:总的数据
const getCheckBox = (t, data) => {
let obj = {}
// //页面加载的时候调用一次
// halfchecked(props.dataList)
// reversecheck(props.dataList)
return (
{
// ccType这个的作用就是在点击选择框后重新渲染一下,默认是false,然后每次取反,在useEffect里面监听ccType,就可以取到强制刷新的作用了
setccType(!ccType)
//点击选择框后调用的方法
checkedItem(data, e.target.checked, mapData(obj, t, props.dataList).permission_id)
// console.log(props.dataList);
//每次点击完都会改变数据里面IsObtain和halfchecked的状态,所有需要再重置一下数据,如果在useEffect里面也监听了props.dataList,就可以不用上面那个ccType了,我是两个都保留了
props.setdataList(props.dataList)
}}
>
{/*这里显示权限的名字*/}
{mapData(obj, t, props.dataList).permission_name}
);
};
//挂载
useEffect(() => {
//初始化页面将数据传入
generateData(props.dataList)
//页面加载的时候调用一次
halfchecked(props.dataList)
reversecheck(props.dataList)
}, [props.dataList, ccType]);
//第十一步,获取选择的数据id
//list,总数据,arr:空数组
const getData = (list, arr) => {
list.map(item => {
if (item.IsObtain || item.halfchecked) {
arr.push(item.permission_id)
}
if (item.childPermissions) {
getData(item.childPermissions, arr)
}
})
}
//第十步,点击保存,这里就是点击保存将全选或者半选的id都传给后端
const addPermission = async () => {
const arr = []
getData(props.dataList, arr)
//打印获取到的id
console.log(arr);
}
return (
{
position: "sticky",
textAlign: "right",
height: "40px",
lineHeight: "40px",
}}
>
{ y: true }}
showHeader={false}
dataSource={dataSource1}
columns={columns1}
/>
)
}
打印出来的id是一个数组
如果大家觉得对表格的魔改不太喜欢或者看不懂的,又想要自己写亿点点样式的,(手动狗头),我还有另一种方法,这种可是自己纯手工打造的,但是我懒得写样式,就放弃了,其实核心代码都差不多。
先看看效果吧:
丑是丑了点,但这可是纯手工打造的,如果谁能把样式改好记得@我一下哟
代码奉上,Child1.tsx
//@ts-nocheck
import { useEffect, useState } from "react";
import { Checkbox, Button, message } from "antd";
const AllPermission = (props: any) => {
const [ccType, setccType] = useState(false)
//半选
const halfchecked = (list) => {
list.map(item => {
if (item.childPermissions) {
let flag = item.childPermissions.some(item => item.IsObtain || item.halfchecked)
item.halfchecked = flag
halfchecked(item.childPermissions)
}
})
}
//反选
const reversecheck = (list) => {
list.map(item => {
if (item.childPermissions) {
let flag = item.childPermissions.every(item => item.IsObtain)
item.IsObtain = flag
reversecheck(item.childPermissions)
}
})
}
//全选
const checkAllbtn = (checked, data) => {
data.map(item => {
item.IsObtain = checked
if (item.childPermissions) {
checkAllbtn(checked, item.childPermissions)
}
})
}
//点击选择框
const checkedItem = (data, checked, id) => {
return data.map(item => {
if (item.permission_id === id) {
item.IsObtain = checked
//全选
if (item.childPermissions) {
checkAllbtn(checked, item.childPermissions)
}
if (item.permission_pid !== "null") {
//反选/半选
reversecheck(props.dataList)
halfchecked(props.dataList)
}
}
//递归
if (item.childPermissions) {
checkedItem(item.childPermissions, checked, id)
//反选/半选 这里不能少
reversecheck(props.dataList)
halfchecked(props.dataList)
}
//反选/半选 这里不能少
reversecheck(props.dataList)
halfchecked(props.dataList)
return item
})
}
//渲染选择框
const treeMethod = (data: any) => {
// let a=[]
return data?.map((item: any, index: any) => {
if (item.childPermissions) {
return (
{ border: "1px solid black", display: "flex", boxSizing: "border-box" }}>
{
setccType(!ccType)
checkedItem(data, e.target.checked, item.permission_id)
props.setdataList(props.dataList)
}}
>{item.permission_name}
{treeMethod(item.childPermissions)}
)
} else {
return (
{ border: "1px solid black" }}>
{
setccType(!ccType)
checkedItem(data, e.target.checked, item.permission_id)
console.log(props.dataList);
props.setdataList(props.dataList)
}}
>{item.permission_name}
);
}
});
};
useEffect(() => {
//页面加载的时候调用一次
halfchecked(props.dataList)
reversecheck(props.dataList)
}, [ccType]);
//获取选择的数据id
const getData = (list, arr) => {
list.map(item => {
if (item.IsObtain || item.halfchecked) {
arr.push(item.permission_id)
}
if (item.childPermissions) {
getData(item.childPermissions, arr)
}
})
}
//点击保存
const addData = async () => {
const arr = []
getData(props.dataList, arr)
console.log(arr);
}
return (
{treeMethod(props.dataList)}
);
};
export default AllPermission;
欢迎分享,转载请注明来源:内存溢出
赞
(0)
打赏
微信扫一扫
支付宝扫一扫
151. 颠倒字符串中的单词 JavaScript实现
上一篇
2022-06-11
509. 斐波那契数 JavaScript实现
下一篇
2022-06-11
评论列表(0条)