Skip to content

Commit 54c3537

Browse files
committed
chore(restore table): n
n
1 parent 72b601d commit 54c3537

File tree

4 files changed

+116
-48
lines changed

4 files changed

+116
-48
lines changed

packages/components/table/PrimaryTable.tsx

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ import useSorter from './hooks/useSorter';
1111
import useFilter from './hooks/useFilter';
1212
import useDragSort from './hooks/useDragSort';
1313
import useAsyncLoading from './hooks/useAsyncLoading';
14-
// import useStickyMultiHeader from './hooks/useStickyMultiHeader';
1514
import { PageInfo, PaginationProps } from '../pagination';
1615
import useClassName from './hooks/useClassName';
1716
import useStyle from './hooks/useStyle';
@@ -68,14 +67,6 @@ const PrimaryTable = forwardRef<PrimaryTableRef, TPrimaryTableProps>((originalPr
6867

6968
const { renderTitleWidthIcon } = useTableHeader({ columns: props.columns });
7069
const { renderAsyncLoading } = useAsyncLoading(props);
71-
72-
// 多级表头sticky效果
73-
// const { clearStickyStyles } = useStickyMultiHeader({
74-
// columns: props.columns,
75-
// isMultipleHeader: !!props.columns.some(col => col.children?.length),
76-
// tableContentRef: primaryTableRef,
77-
// enabled: props.stickyMultiHeader !== false, // 默认启用,可通过props禁用
78-
// });
7970

8071
const primaryTableClasses = {
8172
[tableDraggableClasses.colDraggable]: isColDraggable,

packages/components/table/_example/multi-header.tsx

Lines changed: 114 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -47,13 +47,105 @@ export default function TableExample() {
4747
const [headerAffixedTop, setHeaderAffixedTop] = useState(false);
4848
const [stickyMultiHeader, setStickyMultiHeader] = useState(true);
4949
const [sort, setSort] = useState<TableSort>({ sortBy: 'default', descending: false });
50+
const tableContainerRef = useRef<HTMLDivElement>(null);
5051

5152
const onSortChange: TableProps['onSortChange'] = (sortInfo, context) => {
5253
setSort(sortInfo);
5354
setData([...context.currentDataSource]);
5455
console.log(context);
5556
};
5657

58+
// 多级表头粘性定位逻辑
59+
useEffect(() => {
60+
if (!stickyMultiHeader || !tableContainerRef.current) return;
61+
62+
const tableContainer = tableContainerRef.current;
63+
const tableContent = tableContainer.querySelector('.t-table__content') as HTMLElement;
64+
65+
if (!tableContent) return;
66+
67+
const handleScroll = () => {
68+
const scrollLeft = tableContent.scrollLeft;
69+
const thead = tableContainer.querySelector('.t-table__header--multiple') as HTMLElement;
70+
71+
if (!thead) return;
72+
73+
// 获取所有顶级表头单元格(有colspan的)
74+
const topLevelHeaders = thead.querySelectorAll('tr:first-child th[colspan]') as NodeListOf<HTMLElement>;
75+
76+
let accumulatedWidth = 0;
77+
78+
topLevelHeaders.forEach((header) => {
79+
const colKey = header.getAttribute('data-colkey');
80+
if (!colKey) return;
81+
82+
const cellInner = header.querySelector('.t-table__th-cell-inner') as HTMLElement;
83+
if (!cellInner) return;
84+
85+
// 获取表头相对于表格容器的位置
86+
const headerLeft = header.offsetLeft;
87+
const headerWidth = header.offsetWidth;
88+
const headerRight = headerLeft + headerWidth;
89+
90+
// 判断是否需要粘性定位:表头的左边已经滚动出视野,但右边还在视野内
91+
const shouldStick = scrollLeft > headerLeft && scrollLeft < headerRight;
92+
93+
if (shouldStick) {
94+
// 计算粘性位置,确保不超出表头边界
95+
const maxLeft = headerWidth - 120; // 预留最小显示宽度
96+
const stickyLeft = Math.min(scrollLeft - headerLeft, maxLeft);
97+
98+
console.log('shouldStick', headerLeft, headerRight, scrollLeft, stickyLeft);
99+
// 应用粘性样式
100+
cellInner.style.position = 'relative';
101+
cellInner.style.left = `${stickyLeft}px`;
102+
cellInner.style.zIndex = '10';
103+
} else {
104+
// 移除粘性样式
105+
cellInner.style.position = '';
106+
cellInner.style.left = '';
107+
cellInner.style.zIndex = '';
108+
}
109+
});
110+
};
111+
112+
// 节流处理
113+
let ticking = false;
114+
const throttledScroll = () => {
115+
if (!ticking) {
116+
requestAnimationFrame(() => {
117+
handleScroll();
118+
ticking = false;
119+
});
120+
ticking = true;
121+
}
122+
};
123+
124+
tableContent.addEventListener('scroll', throttledScroll);
125+
126+
// 初始化执行
127+
handleScroll();
128+
129+
return () => {
130+
tableContent.removeEventListener('scroll', throttledScroll);
131+
132+
// 清理样式
133+
const thead = tableContainer.querySelector('.t-table__header--multiple') as HTMLElement;
134+
if (thead) {
135+
const cellInners = thead.querySelectorAll('.t-table__th-cell-inner') as NodeListOf<HTMLElement>;
136+
cellInners.forEach((cellInner) => {
137+
cellInner.style.position = '';
138+
cellInner.style.left = '';
139+
cellInner.style.zIndex = '';
140+
cellInner.style.backgroundColor = '';
141+
cellInner.style.boxShadow = '';
142+
cellInner.style.borderRight = '';
143+
cellInner.style.minWidth = '';
144+
});
145+
}
146+
};
147+
}, [stickyMultiHeader]);
148+
57149
const columns: TableProps['columns'] = [
58150
{
59151
title: '申请人',
@@ -66,7 +158,6 @@ export default function TableExample() {
66158
fixed: fixedLeftCol ? 'left' : undefined,
67159
width: 100,
68160
colKey: 'total_info',
69-
className: stickyMultiHeader ? 'sticky-multi-header' : undefined,
70161
children: [
71162
{
72163
align: 'left',
@@ -113,11 +204,31 @@ export default function TableExample() {
113204
},
114205
],
115206
},
207+
{
208+
colKey: 'field1',
209+
title: '住宿费',
210+
width: 100,
211+
},
212+
{
213+
colKey: 'field3',
214+
title: '交通费',
215+
width: 100,
216+
},
217+
{
218+
colKey: 'field4',
219+
title: '物料费',
220+
width: 100,
221+
},
222+
{
223+
colKey: 'field2',
224+
title: '奖品激励费',
225+
width: 120,
226+
},
116227
{
117228
title: '审批汇总',
118229
colKey: 'instruction',
119230
fixed: fixedRightCol ? 'right' : undefined,
120-
className: stickyMultiHeader ? 'sticky-multi-header' : undefined,
231+
width: 100,
121232
children: [
122233
{
123234
align: 'left',
@@ -160,26 +271,6 @@ export default function TableExample() {
160271
},
161272
],
162273
},
163-
{
164-
colKey: 'field1',
165-
title: '住宿费',
166-
width: 300,
167-
},
168-
{
169-
colKey: 'field3',
170-
title: '交通费',
171-
width: 300,
172-
},
173-
{
174-
colKey: 'field4',
175-
title: '物料费',
176-
width: 300,
177-
},
178-
{
179-
colKey: 'field2',
180-
title: '奖品激励费',
181-
width: 120,
182-
},
183274
{
184275
colKey: 'createTime',
185276
title: '申请时间',
@@ -188,14 +279,7 @@ export default function TableExample() {
188279
},
189280
];
190281
return (
191-
<div>
192-
<style>{`
193-
/* 多级表头粘性定位CSS */
194-
.enable-sticky-multi-header .sticky-multi-header {
195-
position: sticky;
196-
left: 0;
197-
}
198-
`}</style>
282+
<div ref={tableContainerRef}>
199283
<Space direction="vertical" size="large" style={{ width: '100%' }}>
200284
{/* <!-- 按钮操作区域 --> */}
201285
<Space>
@@ -231,7 +315,6 @@ export default function TableExample() {
231315
sort={sort}
232316
onSortChange={onSortChange}
233317
lazyLoad
234-
className={stickyMultiHeader ? 'enable-sticky-multi-header' : undefined}
235318
/>
236319
</Space>
237320
</div>

packages/components/table/interface.ts

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,8 @@ export interface BaseTableProps<T extends TableRowData = TableRowData> extends T
3434
*/
3535
export type SimpleTableProps<T extends TableRowData = TableRowData> = BaseTableProps<T>;
3636

37-
export interface PrimaryTableProps<T extends TableRowData = TableRowData> extends TdPrimaryTableProps<T>, StyledProps {
38-
/**
39-
* 多级表头滚动时是否启用粘性定位效果,让上级表头在滚动时保持可见
40-
* @default true
41-
*/
42-
stickyMultiHeader?: boolean;
43-
}
37+
export interface PrimaryTableProps<T extends TableRowData = TableRowData> extends TdPrimaryTableProps<T>, StyledProps {}
38+
4439
export interface EnhancedTableProps<T extends TableRowData = TableRowData>
4540
extends TdEnhancedTableProps<T>,
4641
StyledProps {}
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1 @@
11
import './index.css';
2-
import './sticky-multi-header.css';

0 commit comments

Comments
 (0)