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 ;
4044 const onHorizontalScroll = ( scrollElement ?: HTMLElement ) => {
41- if ( ! isAffixed && ! isVirtualScroll ) return ;
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,30 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
6367 }
6468 } ;
6569
70+ const onPageHorizontalScroll = ( ) => {
71+ if ( ! isAffixed ) return ;
72+ if ( typeof window === 'undefined' ) return ;
73+
74+ const pageScrollLeft = window . pageXOffset || document . documentElement . scrollLeft || document . body . scrollLeft || 0 ;
75+
76+ if ( lastPageScrollLeftRef . current === pageScrollLeft ) return ;
77+ lastPageScrollLeftRef . current = pageScrollLeft ;
78+
79+ const toUpdateScrollElement = [ affixHeaderRef . current , affixFooterRef . current , horizontalScrollbarRef . current ] ;
80+
81+ toUpdateScrollElement . forEach ( ( el ) => {
82+ if ( ! el ) return ;
83+ // fixedRows 使用 sticky,吸顶表头使用 absolute,需要考虑页面滚动对定位的影响
84+ if ( props . fixedRows && props . fixedRows . length > 0 ) {
85+ // eslint-disable-next-line no-param-reassign
86+ el . style . marginLeft = `-${ pageScrollLeft } px` ;
87+ } else if ( el . style . marginLeft ) {
88+ // eslint-disable-next-line no-param-reassign
89+ el . style . marginLeft = '' ;
90+ }
91+ } ) ;
92+ } ;
93+
6694 // 吸底的元素(footer、横向滚动条、分页器)是否显示
6795 const isAffixedBottomElementShow = ( elementRect : DOMRect , tableRect : DOMRect , headerHeight : number ) =>
6896 tableRect . top + headerHeight < elementRect . top && elementRect . top > elementRect . height ;
@@ -73,7 +101,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
73101 } ;
74102
75103 const updateAffixHeaderOrFooter = ( ) => {
76- if ( ! isAffixed && ! isVirtualScroll ) return ;
104+ if ( ! isAffixed ) return ;
77105 const pos = tableContentRef . current ?. getBoundingClientRect ( ) ;
78106 if ( ! pos ) return ;
79107 const headerRect = tableContentRef . current ?. querySelector ( 'thead' ) ?. getBoundingClientRect ( ) ;
@@ -107,6 +135,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
107135
108136 const onDocumentScroll = ( ) => {
109137 updateAffixHeaderOrFooter ( ) ;
138+ onPageHorizontalScroll ( ) ;
110139 } ;
111140
112141 const onFootScroll = ( ) => {
@@ -173,7 +202,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
173202 on ( horizontalScrollbarRef . current , 'mouseleave' , onScrollbarMouseLeave ) ;
174203 }
175204
176- if ( ( isAffixed || isVirtualScroll ) && tableContentRef . current ) {
205+ if ( isAffixed && tableContentRef . current ) {
177206 on ( tableContentRef . current , 'mouseenter' , onTableContentMouseEnter ) ;
178207 on ( tableContentRef . current , 'mouseleave' , onTableContentMouseLeave ) ;
179208 }
@@ -211,17 +240,30 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
211240 } ) ;
212241 } ;
213242
243+ const addPageHorizontalScrollListener = ( ) => {
244+ if ( typeof window === 'undefined' ) return ;
245+ if ( props . fixedRows && props . fixedRows . length > 0 && isAffixed ) {
246+ onPageHorizontalScroll ( ) ; // initial sync
247+ on ( window , 'scroll' , onPageHorizontalScroll ) ;
248+ }
249+ } ;
250+
214251 useEffect ( ( ) => {
215252 const timer = setTimeout ( ( ) => {
216253 addHorizontalScrollListeners ( ) ;
254+ addPageHorizontalScrollListener ( ) ;
217255 onHorizontalScroll ( ) ;
218256 updateAffixHeaderOrFooter ( ) ;
219257 clearTimeout ( timer ) ;
220258 } ) ;
221-
222- return removeHorizontalScrollListeners ;
259+ return ( ) => {
260+ removeHorizontalScrollListeners ( ) ;
261+ if ( typeof window !== 'undefined' ) {
262+ off ( window , 'scroll' , onPageHorizontalScroll ) ;
263+ }
264+ } ;
223265 // eslint-disable-next-line react-hooks/exhaustive-deps
224- } , [ affixHeaderRef , affixFooterRef , horizontalScrollbarRef , tableContentRef , showElement ] ) ;
266+ } , [ affixHeaderRef , affixFooterRef , horizontalScrollbarRef , tableContentRef , showElement , props . fixedRows ] ) ;
225267
226268 useEffect ( ( ) => {
227269 addVerticalScrollListener ( ) ;
@@ -234,6 +276,7 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
234276 useEffect ( ( ) => {
235277 addHorizontalScrollListeners ( ) ;
236278 onHorizontalScroll ( ) ;
279+ addPageHorizontalScrollListener ( ) ;
237280 // eslint-disable-next-line react-hooks/exhaustive-deps
238281 } , [
239282 props . data ,
@@ -242,11 +285,13 @@ export default function useAffix(props: TdBaseTableProps, { showElement }: { sho
242285 props . footerAffixedBottom ,
243286 props . horizontalScrollAffixedBottom ,
244287 props . lazyLoad ,
288+ props . fixedRows ,
245289 ] ) ;
246290
247291 const setTableContentRef = ( tableContent : HTMLDivElement ) => {
248292 tableContentRef . current = tableContent ;
249293 addVerticalScrollListener ( ) ;
294+ addPageHorizontalScrollListener ( ) ;
250295 } ;
251296
252297 return {
0 commit comments