Skip to content

Commit 75ee006

Browse files
authored
feat: onCell support rowSpan & colSpan (#710)
* docs: new example * chore: add consumer * chore: clean up * chore: fix for render * test: Test coverage
1 parent 710f8a7 commit 75ee006

File tree

9 files changed

+370
-108
lines changed

9 files changed

+370
-108
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## colspan-rowspan-legacy
2+
3+
<code src="../examples/colspan-rowspan-legacy.tsx">
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
import React from 'react';
2+
import Table from 'rc-table';
3+
import '../../assets/index.less';
4+
import { ColumnsType, RenderedCell } from '@/interface';
5+
6+
interface RecordType {
7+
a?: string;
8+
b?: string;
9+
c?: string;
10+
d?: string;
11+
e?: string;
12+
key?: string;
13+
}
14+
15+
const columns: ColumnsType<RecordType> = [
16+
{
17+
title: '手机号',
18+
dataIndex: 'a',
19+
colSpan: 2,
20+
width: 100,
21+
key: 'a',
22+
render(o, row, index) {
23+
const obj: RenderedCell<RecordType> = {
24+
children: o,
25+
props: {},
26+
};
27+
// 设置第一行为链接
28+
if (index === 0) {
29+
obj.children = <a href="#">{o}</a>;
30+
}
31+
// 第5行合并两列
32+
if (index === 4) {
33+
obj.props.colSpan = 2;
34+
}
35+
36+
if (index === 5) {
37+
obj.props.colSpan = 6;
38+
}
39+
return obj;
40+
},
41+
},
42+
{
43+
title: '电话',
44+
dataIndex: 'b',
45+
colSpan: 0,
46+
width: 100,
47+
key: 'b',
48+
render(o, row, index) {
49+
const obj: RenderedCell<RecordType> = {
50+
children: o,
51+
props: {},
52+
};
53+
// 列合并掉的表格设置colSpan=0,不会去渲染
54+
if (index === 4 || index === 5) {
55+
obj.props.colSpan = 0;
56+
}
57+
return obj;
58+
},
59+
},
60+
{
61+
title: 'Name',
62+
dataIndex: 'c',
63+
width: 100,
64+
key: 'c',
65+
render(o, row, index) {
66+
const obj: RenderedCell<RecordType> = {
67+
children: o,
68+
props: {},
69+
};
70+
71+
if (index === 5) {
72+
obj.props.colSpan = 0;
73+
}
74+
return obj;
75+
},
76+
},
77+
{
78+
title: 'Address',
79+
dataIndex: 'd',
80+
width: 200,
81+
key: 'd',
82+
render(o, row, index) {
83+
const obj: RenderedCell<RecordType> = {
84+
children: o,
85+
props: {},
86+
};
87+
if (index === 0) {
88+
obj.props.rowSpan = 2;
89+
}
90+
if (index === 1 || index === 5) {
91+
obj.props.rowSpan = 0;
92+
}
93+
94+
if (index === 5) {
95+
obj.props.colSpan = 0;
96+
}
97+
98+
return obj;
99+
},
100+
},
101+
{
102+
title: 'Gender',
103+
dataIndex: 'e',
104+
width: 200,
105+
key: 'e',
106+
render(o, row, index) {
107+
const obj: RenderedCell<RecordType> = {
108+
children: o,
109+
props: {},
110+
};
111+
if (index === 5) {
112+
obj.props.colSpan = 0;
113+
}
114+
return obj;
115+
},
116+
},
117+
{
118+
title: 'Operations',
119+
dataIndex: '',
120+
key: 'f',
121+
render(o, row, index) {
122+
if (index === 5) {
123+
return {
124+
props: {
125+
colSpan: 0,
126+
},
127+
};
128+
}
129+
return <a href="#">Operations</a>;
130+
},
131+
},
132+
];
133+
134+
const data: RecordType[] = [
135+
{ a: '13812340987', b: '0571-12345678', c: '张三', d: '文一西路', e: 'Male', key: '1' },
136+
{ a: '13812340986', b: '0571-98787658', c: '张夫人', d: '文一西路', e: 'Female', key: '2' },
137+
{ a: '13812988888', b: '0571-099877', c: '李四', d: '文二西路', e: 'Male', key: '3' },
138+
{ a: '1381200008888', b: '0571-099877', c: '王五', d: '文二西路', e: 'Male', key: '4' },
139+
{ a: '0571-88888110', c: '李警官', d: '武林门', e: 'Male', key: '5' },
140+
{ a: '资料统计完毕于xxxx年xxx月xxx日', key: '6' },
141+
];
142+
143+
const Demo = () => (
144+
<div>
145+
<h2>colSpan & rowSpan</h2>
146+
<Table columns={columns} data={data} className="table" />
147+
</div>
148+
);
149+
150+
export default Demo;

docs/examples/colspan-rowspan.tsx

Lines changed: 30 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,21 @@ const columns: ColumnsType<RecordType> = [
2020
width: 100,
2121
key: 'a',
2222
render(o, row, index) {
23-
const obj: RenderedCell<RecordType> = {
24-
children: o,
25-
props: {},
26-
};
27-
// 设置第一行为链接
28-
if (index === 0) {
29-
obj.children = <a href="#">{o}</a>;
30-
}
23+
return index === 0 ? <a href="#">{o}</a> : o;
24+
},
25+
onCell: (_, index) => {
26+
const props: React.TdHTMLAttributes<HTMLTableCellElement> = {};
27+
3128
// 第5行合并两列
3229
if (index === 4) {
33-
obj.props.colSpan = 2;
30+
props.colSpan = 2;
3431
}
3532

3633
if (index === 5) {
37-
obj.props.colSpan = 6;
34+
props.colSpan = 6;
3835
}
39-
return obj;
36+
37+
return props;
4038
},
4139
},
4240
{
@@ -45,88 +43,72 @@ const columns: ColumnsType<RecordType> = [
4543
colSpan: 0,
4644
width: 100,
4745
key: 'b',
48-
render(o, row, index) {
49-
const obj: RenderedCell<RecordType> = {
50-
children: o,
51-
props: {},
52-
};
46+
onCell(_, index) {
5347
// 列合并掉的表格设置colSpan=0,不会去渲染
5448
if (index === 4 || index === 5) {
55-
obj.props.colSpan = 0;
49+
return { colSpan: 0 };
5650
}
57-
return obj;
51+
return {};
5852
},
5953
},
6054
{
6155
title: 'Name',
6256
dataIndex: 'c',
6357
width: 100,
6458
key: 'c',
65-
render(o, row, index) {
66-
const obj: RenderedCell<RecordType> = {
67-
children: o,
68-
props: {},
69-
};
70-
59+
onCell(_, index) {
7160
if (index === 5) {
72-
obj.props.colSpan = 0;
61+
return { colSpan: 0 };
7362
}
74-
return obj;
63+
return {};
7564
},
7665
},
7766
{
7867
title: 'Address',
7968
dataIndex: 'd',
8069
width: 200,
8170
key: 'd',
82-
render(o, row, index) {
83-
const obj: RenderedCell<RecordType> = {
84-
children: o,
85-
props: {},
86-
};
71+
onCell(_, index) {
72+
const props: React.TdHTMLAttributes<HTMLTableCellElement> = {};
8773
if (index === 0) {
88-
obj.props.rowSpan = 2;
74+
props.rowSpan = 2;
8975
}
9076
if (index === 1 || index === 5) {
91-
obj.props.rowSpan = 0;
77+
props.rowSpan = 0;
9278
}
9379

9480
if (index === 5) {
95-
obj.props.colSpan = 0;
81+
props.colSpan = 0;
9682
}
97-
98-
return obj;
83+
return props;
9984
},
10085
},
10186
{
10287
title: 'Gender',
10388
dataIndex: 'e',
10489
width: 200,
10590
key: 'e',
106-
render(o, row, index) {
107-
const obj: RenderedCell<RecordType> = {
108-
children: o,
109-
props: {},
110-
};
91+
onCell(_, index) {
11192
if (index === 5) {
112-
obj.props.colSpan = 0;
93+
return { colSpan: 0 };
11394
}
114-
return obj;
95+
return {};
11596
},
11697
},
11798
{
11899
title: 'Operations',
119100
dataIndex: '',
120101
key: 'f',
121-
render(o, row, index) {
102+
render() {
103+
return <a href="#">Operations</a>;
104+
},
105+
onCell(_, index) {
122106
if (index === 5) {
123107
return {
124-
props: {
125-
colSpan: 0,
126-
},
108+
colSpan: 0,
127109
};
128110
}
129-
return <a href="#">Operations</a>;
111+
return {};
130112
},
131113
},
132114
];

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@types/jest": "^26.0.3",
6565
"@types/react": "^17.0.35",
6666
"@types/react-dom": "^17.0.10",
67+
"@types/shallowequal": "^1.1.1",
6768
"@umijs/fabric": "^2.0.0",
6869
"cross-env": "^7.0.0",
6970
"dumi": "^1.1.9",

src/Body/index.tsx

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,17 @@ function Body<RecordType>({
3131
emptyNode,
3232
childrenColumnName,
3333
}: BodyProps<RecordType>) {
34-
const [startRow, setStartRow] = React.useState(-1);
35-
const [endRow, setEndRow] = React.useState(-1);
3634
const { onColumnResize } = React.useContext(ResizeContext);
3735
const { prefixCls, getComponent } = React.useContext(TableContext);
3836
const { flattenColumns } = React.useContext(BodyContext);
3937

4038
const flattenData: { record: RecordType; indent: number; index: number }[] =
4139
useFlattenRecords<RecordType>(data, childrenColumnName, expandedKeys, getRowKey);
4240

41+
// ====================== Hover =======================
42+
const [startRow, setStartRow] = React.useState(-1);
43+
const [endRow, setEndRow] = React.useState(-1);
44+
4345
const onHover = React.useCallback((start: number, end: number) => {
4446
setStartRow(start);
4547
setEndRow(end);
@@ -50,7 +52,8 @@ function Body<RecordType>({
5052
[onHover, startRow, endRow],
5153
);
5254

53-
return React.useMemo(() => {
55+
// ====================== Render ======================
56+
const bodyNode = React.useMemo(() => {
5457
const WrapperComponent = getComponent(['body', 'wrapper'], 'tbody');
5558
const trComponent = getComponent(['body', 'row'], 'tr');
5659
const tdComponent = getComponent(['body', 'cell'], 'td');
@@ -98,20 +101,18 @@ function Body<RecordType>({
98101
const columnsKey = getColumnsKey(flattenColumns);
99102

100103
return (
101-
<HoverContext.Provider value={hoverContext}>
102-
<WrapperComponent className={`${prefixCls}-tbody`}>
103-
{/* Measure body column width with additional hidden col */}
104-
{measureColumnWidth && (
105-
<MeasureRow
106-
prefixCls={prefixCls}
107-
columnsKey={columnsKey}
108-
onColumnResize={onColumnResize}
109-
/>
110-
)}
111-
112-
{rows}
113-
</WrapperComponent>
114-
</HoverContext.Provider>
104+
<WrapperComponent className={`${prefixCls}-tbody`}>
105+
{/* Measure body column width with additional hidden col */}
106+
{measureColumnWidth && (
107+
<MeasureRow
108+
prefixCls={prefixCls}
109+
columnsKey={columnsKey}
110+
onColumnResize={onColumnResize}
111+
/>
112+
)}
113+
114+
{rows}
115+
</WrapperComponent>
115116
);
116117
}, [
117118
data,
@@ -127,8 +128,9 @@ function Body<RecordType>({
127128
onColumnResize,
128129
rowExpandable,
129130
flattenData,
130-
hoverContext,
131131
]);
132+
133+
return <HoverContext.Provider value={hoverContext}>{bodyNode}</HoverContext.Provider>;
132134
}
133135

134136
const MemoBody = React.memo(Body);

0 commit comments

Comments
 (0)