11.3 笔记
项目整理
场景1 table展开行使用
描述
INFO
现在有一种需求,希望table
呈现出Tree
的效果,并且可以支持搜索高亮功能
思路
- 主要就是利用
expandable
这个属性
在里面主要就是维护expandRowKeys
和onExpand
这两个属性
1. `expandRowKeys`:展开行,控制属性,但是不要和`**defaultExpandedRowKeys**`**一起使用**
2. `onExpand`:展开图标时触发
- 在数据一上来,我就希望可以默认将所有数据全部展开,这样的好处是,可以方便后续高亮展示
默认展示,我们会使用**defaultExpandedRowKeys**
这个属性,但是这个属性不可以和**expandRowKeys**
一起使用,可能两个属性会“打架”
那么我们就只能自己去维护**expandRowKeys**
,也就是我们在拿到**TreeData**
的时候,就去收集所有的**id**
,这样**Table**
就会自动展开
- 如何做到满足搜索条件的高亮展示?
使用的rowClassName
这个属性,但是最主要的是怎么判断当前满足条件呢?
1. 当我们没有加上任何查询条件,也就是希望搜索所有的时候,我们默认不需要高亮
2. 在所有的`tableData`中寻找是否有数据满足`form`表单里面的数据,收集`id`(**递归:因为有children**)
3. 后续我们只需要判断:当前row的id是否在`匹配到的ids`里面
- 查看下级
我们点击查看下级的时候,需要实时的维护expandRowKeys
代码
- 因为这里面涉及,查看下级,并且查看下级会导致
dataSource
直接发生改变,所以这边并没有使用request
,而是我们自己来维护dataSource
onSubmit
:就是自己调用ProTable
上提交表单时触发onReset
:重置表单时触发
typescript
<ProTable
// some useless codes
dataSource={dataSource}
rowKey={"id"}
pagination={false}
expandable={{
expandedRowKeys,
onExpand,
}}
// 提交表单时候触发
onSubmit={(params) => {
getTableData(params);
}}
// 重置表单时触发
onReset={() => {
getTableData({});
}}
// 匹配到的行高亮
rowClassName={(record) => {
return isMatchData(record) ? "light-row" : "";
}}
/>
因为希望页面一上来就全部展开,所以在每次请求数据时候:不仅获取到treeData
而且将TreeData
里面的ids
也收集起来
typescript
export async function getDepartmentList(params) {
const { simLevel, ...left } = params;
const res = await request("/v2/web_api/company_depart/new/company_depart_list", {
method: "post",
data: {
...left,
simLeave: Number(simLevel),
},
});
// 获取ids
const expandKeys = collectParentId(JSON.parse(JSON.stringify([res.model])));
const data = formatTreeData(res.model);
// 匹配参数,找到对应的部门
return {
data: [data],
success: res.success,
expandKeys,
};
}
收集所有ids的时候,不要只是收集部门的id
,虽然确实是只有部门才会展开,人员没有下级。
但是如果你现在没有收集,那么后续,高亮进行匹配的时候就会出现问题
typescript
export const collectParentId = (data: any) => {
const arr: string[] = [];
const render = (treeDatas: any) => {
treeDatas.forEach((item: any) => {
arr.push(item.id);
if (item.childDeparentList) {
render(item.childDeparentList);
}
if (item.childUserList) {
render(item.childUserList);
}
});
};
render(data);
return arr;
};
因为页面展示的时候,每一行的row
的类型其实是不同的,包含人员和部门,这时候我们就需要调整一下格式
children
:人员在上面,部门在下面childDeparentList
:可能会存在下级,所以需要递归,但是人员下面一定不存在下级,没必要递归
typescript
export const formatTreeData = (data: TreeData): any => {
const { childDeparentList, childUserList, ...rest } = data;
const children = (childDeparentList || []).map((item) => {
return formatTreeData(item);
});
const users = (childUserList || []).map((item) => {
return item;
});
// 将users 放到children中
const newChildren = [...users, ...children];
if (!newChildren.length) {
return { ...rest, children: undefined };
}
return { ...rest, children: newChildren };
};
我们这里的判断条件只需要满足其中一个,那么就可以高亮了
因为加了搜索条件的TreeData
其实本身就已经满足了搜索条件,所以我们要做的就是对这个数据直接高亮就可以了
typescript
export const findIdByForm = (data: tableData[], form: any) => {
const id: string[] = [];
const render = (treeDatas: tableData[]) => {
treeDatas.forEach((item) => {
if (item.id === form.departId || item.id === form.userId || Number(item.simLevel) === Number(form.simLevel)) {
id.push(item.id);
}
if (item.children) {
render(item.children as tableData[]);
}
});
};
render(data);
return id;
};
每次获取TreeData的时候:
- 收集
TreeData
数据 - 收集
TreeData
里面所有的ids
,用于展开 - 收集和当前搜索条件匹配到
ids
,用于后续高亮
typescript
async function getTableData(params: any) {
const res = await getDepartmentList(params);
if (res.success) {
const { data, expandKeys } = res;
setDataSource(data as never[]);
setExpandedRowKeys(expandKeys);
const ids = findIdByForm(data, formRef.current?.getFieldsValue());
setLastKeys(ids);
}
}
用户点击获取下级的时候
- 直接获取到下级应该有的数据,在获取到就对数据进行
format
,使他满足展示的格式 - 去
dataSource
里面匹配id(当前点击的id)
,将获取到的数据替换到children
上面
typescript
const checkMore = (id: string) => {
// 设置展开行的rowKeys
setExpandedRowKeys([...expandedRowKeys, id]);
getDepartmentChildList(id).then((res) => {
if (res.success) {
const { data } = res;
const cloneData = lodash.cloneDeep(dataSource)[0];
const datas = findTreeData({
data: cloneData,
id,
newChidren: data[0].children,
});
setDataSource([datas] as never[]);
};
});
};
查询下级的数据,同样的,也需要对数据进行一个format
typescript
export async function getDepartmentChildList(params, fn) {
const res = await request("/v2/web_api/company_depart/company_depart_info", {
method: "post",
data: {
id: params,
}
});
const data = formatTreeData(res.model);
return {
data: [data],
success: res.success,
};
}
我们需要在datasource
里面去匹配到当前点击的id
,然后将他的children
替换为newChildren
typescript
interface tableData {
simLevel: number;
areaCode: string;
caId: string;
caName: string;
id: string;
isArea: number;
name: string;
parentId: string;
children: tableData[] | User[];
}
interface IFindTreeData {
data: tableData;
id: string;
newChidren: tableData[] | User[];
}
export const findTreeData = (params: IFindTreeData): tableData => {
const { data, id, newChidren } = params;
if (data.id === id) {
return { ...data, children: newChidren };
}
// 在datasource里面去寻找数据
if (data.children) {
return {
...data,
children: data.children.map((item) => {
return findTreeData({ data: item as tableData, id, newChidren });
}),
};
}
return data;
};