您好,登錄后才能下訂單哦!
本篇內容主要講解“antd4里table滾動如何實現”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“antd4里table滾動如何實現”吧!
首先antd4的table的底層實現是rc-table,就從rc-table來看看。
場景:Table內容區域大于容器Table寬度,并且Table設置了scrollX,Header、Footer都有, 才關注同頻滾動
那么是如何實現的?
監聽onScroll方法獲取到滾動條向左的滾動的距離scrollLeft;
同時給三個dom設置scrollLeft
先看一般的onScroll實現
監聽onScroll獲取scrollLeft
設置header、footer、tableBody的scrollLeft
下面是偽代碼哈
const onScroll = (e: ScrollEvent) => { // 拿到scrollLeft const scrollLeft = e.target.scrollLeft // 給所有的header、footer、table-body設置scrollLeft header.scrollLeft = scrollLeft footer.scrollLeft = scrollLeft tableBody.scrollLeft = scrollLeft }
源碼里onScroll的實現
const onScroll = ({ currentTarget, scrollLeft, }: { currentTarget: HTMLElement; scrollLeft?: number; }) => { const mergedScrollLeft = typeof scrollLeft === 'number' ? scrollLeft : currentTarget.scrollLeft; const compareTarget = currentTarget || EMPTY_SCROLL_TARGET; if (!getScrollTarget() || getScrollTarget() === compareTarget) { setScrollTarget(compareTarget); //一個 滾動需要 控制 header、body、summary、stickyScrollBar所有同步滾動 // header設置scrollLeft scrollHeaderRef.current = mergedScrollLeft // body 設置scrollLeft scrollBodyRef.current = mergedScrollLeft } };
對比兩個的實現,可以看到rc-table里的實現多了一個入參scrollLeft和一個if判斷;
為什么多了一個入參、一個判斷?繼續往下看?
用組件FixedHolder實現,給FixedHolder綁定ref;
監聽的是onWheel, 不是onScroll;
為什么監聽onWheel不是onScroll?
React.useEffect(() => { function onWheel(e: WheelEvent) { // deltaX: Returns a double representing the horizontal scroll amount const { currentTarget, deltaX } = e as unknown as React.WheelEvent<HTMLDivElement>; // 避免觸發不必要滾動, 是一種優化 if (deltaX) { onScroll({ currentTarget, scrollLeft: currentTarget.scrollLeft + deltaX }); e.preventDefault(); } } fixHolder.current?.addEventListener('wheel', onWheel); return () => { fixHolder.current?.removeEventListener('wheel', onWheel); }; }, []);
不要將 onscroll 與 onwheel混淆。onwheel 是鼠標滾輪旋轉,而 onscroll 處理的是對象內部內容區的滾動事件。
當dom滿足下面任意一條的時候,不會觸發onScroll;
overflow:hidden
滾動條不存在
FixHolder組件
設置了樣式overflow:hidden;
<div style={{ overflow: 'hidden', ...(isSticky ? { top: stickyTopOffset, bottom: stickyBottomOffset } : {}), }} ref={setScrollRef} className={classNames(className, { [stickyClassName]: !!stickyClassName, })} /> <table style={{ tableLayout: 'fixed', visibility: noData || mergedColumnWidth ? null : 'hidden', }} > {(!noData || !maxContentScroll || allFlattenColumnsWithWidth) && ( <ColGroup colWidths={mergedColumnWidth ? [...mergedColumnWidth, combinationScrollBarSize] : []} columCount={columCount + 1} columns={flattenColumnsWithScrollbar} /> )} {children({ ...props, stickyOffsets: headerStickyOffsets, columns: columnsWithScrollbar, flattenColumns: flattenColumnsWithScrollbar, })} </table> </div>
通過ref,調用useCallback賦值dom;利用scrollRef.current監聽wheel事件,轉成onScroll,增加入參scrollLeft;
const setScrollRef = React.useCallback((element: HTMLElement) => { scrollRef.current = element; }, []);
當然是監聽onScroll事件;
給Tables設置scrollX的情況下,TableBody設置樣式{overflow-x: auto}這樣會有同頻滾動
<div style={ ...scrollXStyle, ...scrollYStyle } onScroll={onScroll} ref={scrollBodyRef} > <TableComponent> {bodyColGroup} {bodyTable} </TableComponent> </div>
獲得當前正在執行的dom
const [setScrollTarget, getScrollTarget] = useTimeoutLock(null);
getScrollTarget用來獲得當前正在執行的dom
使用useState來存儲正在執行的dom; 當組件重新渲染,dom更新,此時正在執行的dom,在下一個render的時候,就變了;useRef在下一次渲染之前不重新賦值,還是保留和上一次一樣的值;
源碼里使用useRef + setTimeout實現;useRef是用來存放當前正在執行的dom;setTimeout用來節流;
其中getState獲取正在執行當前state,可能是空的;setState設置當前的State,并且在100ms以后清空設置的狀態;
export function useTimeoutLock<State>(defaultState?: State): [(state: State) => void, () => State | null] { const frameRef = useRef<State | null>(defaultState || null); const timeoutRef = useRef<number>(); function cleanUp() { window.clearTimeout(timeoutRef.current); } function setState(newState: State) { frameRef.current = newState; // 清空上一次的定時器 cleanUp(); timeoutRef.current = window.setTimeout(() => { frameRef.current = null; timeoutRef.current = undefined; }, 100); } function getState() { return frameRef.current; } useEffect(() => cleanUp, []); return [setState, getState]; }
onScroll為什么設置if判斷
getScrollTarget()調用onScroll的之前,是否有滾動的dom; 沒有就更新;有,判斷是否和觸發onScroll是相同Dom;是,更新;目的是為了避免執行上一個onScroll的時候,下一個onScroll執行,陷入循環,就相當于節流了;hooks版本的節流
const compareTarget = currentTarget || EMPTY_SCROLL_TARGET; // 固定滾動項 // 在處理上一個滾動的時候,禁止下一個也滾動執行onScroll if (!getScrollTarget() || getScrollTarget() === compareTarget) { setScrollTarget(compareTarget); }
看這塊邏輯的時候,優化細節;從hooks的角度,實現節流;wheel和scroll都是滾動,但是也有區別;并且在react里支持dom綁定onScroll、onWheel。
到此,相信大家對“antd4里table滾動如何實現”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。