1- import { useState , useRef , useMemo , useEffect } from 'react' ;
2- import { TdBaseTableProps } from '../type' ;
3- import { AffixProps } from '../../affix' ;
1+ import { useEffect , useMemo , useRef , useState } from 'react' ;
42import { off , on } from '../../_util/listener' ;
3+ import type { AffixProps } from '../../affix' ;
4+ import type { TdBaseTableProps } from '../type' ;
55
66/**
77 * 1. 表头吸顶(普通表头吸顶 和 虚拟滚动表头吸顶)
@@ -11,6 +11,9 @@ import { off, on } from '../../_util/listener';
1111 */
1212export default function useAffix ( props : TdBaseTableProps , { showElement } : { showElement : boolean } ) {
1313 const tableContentRef = useRef < HTMLDivElement > ( null ) ;
14+ const lastTableScrollLeftRef = useRef < number > ( 0 ) ;
15+ const lastPageScrollLeftRef = useRef < number > ( 0 ) ;
16+
1417 // 吸顶表头
1518 const affixHeaderRef = useRef < HTMLDivElement > ( null ) ;
1619 // 吸底表尾
@@ -19,6 +22,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
1922 const horizontalScrollbarRef = useRef < HTMLDivElement > ( null ) ;
2023 // 吸底分页器
2124 const paginationRef = useRef < HTMLDivElement > ( null ) ;
25+
2226 // 当表格完全滚动消失在视野时,需要隐藏吸顶表头
2327 const [ showAffixHeader , setShowAffixHeader ] = useState ( true ) ;
2428 // 当表格完全滚动消失在视野时,需要隐藏吸底尾部
@@ -32,23 +36,23 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
3236 ) ;
3337
3438 const isAffixed = useMemo (
35- ( ) => ! ! ( props . headerAffixedTop || props . footerAffixedBottom || props . horizontalScrollAffixedBottom ) ,
36- [ props . footerAffixedBottom , props . headerAffixedTop , props . horizontalScrollAffixedBottom ] ,
39+ ( ) =>
40+ ! ! ( isVirtualScroll || props . headerAffixedTop || props . footerAffixedBottom || props . horizontalScrollAffixedBottom ) ,
41+ [ isVirtualScroll , props . footerAffixedBottom , props . headerAffixedTop , props . horizontalScrollAffixedBottom ] ,
3742 ) ;
3843
39- let lastScrollLeft = 0 ;
40- const onHorizontalScroll = ( scrollElement ?: HTMLElement ) => {
41- if ( ! isAffixed && ! isVirtualScroll ) return ;
44+ const onTableHorizontalScroll = ( scrollElement ?: HTMLElement ) => {
45+ if ( ! isAffixed ) return ;
4246 let target = scrollElement ;
4347 if ( ! target && tableContentRef . current ) {
44- lastScrollLeft = 0 ;
48+ lastTableScrollLeftRef . current = 0 ;
4549 target = tableContentRef . current ;
4650 }
4751 if ( ! target ) return ;
4852 const left = target . scrollLeft ;
4953 // 如果 lastScrollLeft 等于 left,说明不是横向滚动,不需要更新横向滚动距离
50- if ( lastScrollLeft === left ) return ;
51- lastScrollLeft = left ;
54+ if ( lastTableScrollLeftRef . current === left ) return ;
55+ lastTableScrollLeftRef . current = left ;
5256 // 表格内容、吸顶表头、吸底表尾、吸底横向滚动更新
5357 const toUpdateScrollElement = [
5458 tableContentRef . current ,
@@ -63,6 +67,28 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
6367 }
6468 } ;
6569
70+ const onPageHorizontalScroll = ( ) => {
71+ if ( ! isAffixed || ! props . fixedRows ?. length ) return ;
72+
73+ const pageScrollLeft = window . pageXOffset || document . documentElement . scrollLeft || document . body . scrollLeft || 0 ;
74+ if ( lastPageScrollLeftRef . current === pageScrollLeft ) return ;
75+ lastPageScrollLeftRef . current = pageScrollLeft ;
76+
77+ const toUpdateScrollElement = [ affixHeaderRef . current , affixFooterRef . current , horizontalScrollbarRef . current ] ;
78+ toUpdateScrollElement . forEach ( ( element ) => {
79+ if ( element ) {
80+ // 固定行会使用绝对定位,吸顶表头的位置计算需要考虑页面级别的滚动偏移
81+ if ( props . fixedRows . length ) {
82+ // eslint-disable-next-line no-param-reassign
83+ element . style . marginLeft = `-${ pageScrollLeft } px` ;
84+ } else if ( element . style . marginLeft ) {
85+ // eslint-disable-next-line no-param-reassign
86+ element . style . marginLeft = '' ;
87+ }
88+ }
89+ } ) ;
90+ } ;
91+
6692 // 吸底的元素(footer、横向滚动条、分页器)是否显示
6793 const isAffixedBottomElementShow = ( elementRect : DOMRect , tableRect : DOMRect , headerHeight : number ) =>
6894 tableRect . top + headerHeight < elementRect . top && elementRect . top > elementRect . height ;
@@ -73,7 +99,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
7399 } ;
74100
75101 const updateAffixHeaderOrFooter = ( ) => {
76- if ( ! isAffixed && ! isVirtualScroll ) return ;
102+ if ( ! isAffixed ) return ;
77103 const pos = tableContentRef . current ?. getBoundingClientRect ( ) ;
78104 if ( ! pos ) return ;
79105 const headerRect = tableContentRef . current ?. querySelector ( 'thead' ) ?. getBoundingClientRect ( ) ;
@@ -105,24 +131,25 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
105131 }
106132 } ;
107133
108- const onDocumentScroll = ( ) => {
134+ const onPageScroll = ( ) => {
109135 updateAffixHeaderOrFooter ( ) ;
136+ onPageHorizontalScroll ( ) ;
110137 } ;
111138
112139 const onFootScroll = ( ) => {
113- onHorizontalScroll ( affixFooterRef . current ) ;
140+ onTableHorizontalScroll ( affixFooterRef . current ) ;
114141 } ;
115142
116143 const onHeaderScroll = ( ) => {
117- onHorizontalScroll ( affixHeaderRef . current ) ;
144+ onTableHorizontalScroll ( affixHeaderRef . current ) ;
118145 } ;
119146
120147 const horizontalScrollbarScroll = ( ) => {
121- onHorizontalScroll ( horizontalScrollbarRef . current ) ;
148+ onTableHorizontalScroll ( horizontalScrollbarRef . current ) ;
122149 } ;
123150
124151 const onTableContentScroll = ( ) => {
125- onHorizontalScroll ( tableContentRef . current ) ;
152+ onTableHorizontalScroll ( tableContentRef . current ) ;
126153 } ;
127154
128155 const onFootMouseEnter = ( ) => {
@@ -173,7 +200,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
173200 on ( horizontalScrollbarRef . current , 'mouseleave' , onScrollbarMouseLeave ) ;
174201 }
175202
176- if ( ( isAffixed || isVirtualScroll ) && tableContentRef . current ) {
203+ if ( isAffixed && tableContentRef . current ) {
177204 on ( tableContentRef . current , 'mouseenter' , onTableContentMouseEnter ) ;
178205 on ( tableContentRef . current , 'mouseleave' , onTableContentMouseLeave ) ;
179206 }
@@ -198,14 +225,14 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
198225 }
199226 } ;
200227
201- const addVerticalScrollListener = ( ) => {
228+ const addPageScrollListener = ( ) => {
202229 if ( typeof document === 'undefined' ) return ;
203230 if ( ! isAffixed && ! props . paginationAffixedBottom ) return ;
204231 const timer = setTimeout ( ( ) => {
205232 if ( isAffixed || props . paginationAffixedBottom ) {
206- on ( document , 'scroll' , onDocumentScroll ) ;
233+ on ( document , 'scroll' , onPageScroll ) ;
207234 } else {
208- off ( document , 'scroll' , onDocumentScroll ) ;
235+ off ( document , 'scroll' , onPageScroll ) ;
209236 }
210237 clearTimeout ( timer ) ;
211238 } ) ;
@@ -214,26 +241,28 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
214241 useEffect ( ( ) => {
215242 const timer = setTimeout ( ( ) => {
216243 addHorizontalScrollListeners ( ) ;
217- onHorizontalScroll ( ) ;
244+ onTableHorizontalScroll ( ) ;
218245 updateAffixHeaderOrFooter ( ) ;
219246 clearTimeout ( timer ) ;
220247 } ) ;
221-
222- return removeHorizontalScrollListeners ;
248+ return ( ) => {
249+ removeHorizontalScrollListeners ( ) ;
250+ } ;
223251 // eslint-disable-next-line react-hooks/exhaustive-deps
224- } , [ affixHeaderRef , affixFooterRef , horizontalScrollbarRef , tableContentRef , showElement ] ) ;
252+ } , [ affixHeaderRef , affixFooterRef , horizontalScrollbarRef , tableContentRef , showElement , props . fixedRows ] ) ;
225253
226254 useEffect ( ( ) => {
227- addVerticalScrollListener ( ) ;
255+ addPageScrollListener ( ) ;
228256 return ( ) => {
229- off ( document , 'scroll' , onDocumentScroll ) ;
257+ if ( typeof document === 'undefined' ) return ;
258+ off ( document , 'scroll' , onPageScroll ) ;
230259 } ;
231260 // eslint-disable-next-line react-hooks/exhaustive-deps
232- } , [ isAffixed ] ) ;
261+ } , [ isAffixed , props . fixedRows ] ) ;
233262
234263 useEffect ( ( ) => {
235264 addHorizontalScrollListeners ( ) ;
236- onHorizontalScroll ( ) ;
265+ onTableHorizontalScroll ( ) ;
237266 // eslint-disable-next-line react-hooks/exhaustive-deps
238267 } , [
239268 props . data ,
@@ -242,11 +271,12 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
242271 props . footerAffixedBottom ,
243272 props . horizontalScrollAffixedBottom ,
244273 props . lazyLoad ,
274+ props . fixedRows ,
245275 ] ) ;
246276
247277 const setTableContentRef = ( tableContent : HTMLDivElement ) => {
248278 tableContentRef . current = tableContent ;
249- addVerticalScrollListener ( ) ;
279+ addPageScrollListener ( ) ;
250280 } ;
251281
252282 return {
@@ -257,7 +287,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
257287 affixFooterRef,
258288 horizontalScrollbarRef,
259289 paginationRef,
260- onHorizontalScroll ,
290+ onTableHorizontalScroll ,
261291 setTableContentRef,
262292 updateAffixHeaderOrFooter,
263293 } ;
0 commit comments