莱芜金点子最新招工,长春seo推广外包,东莞自助建站平台,做网站都需要买什么问题rc-table里Header、Footer、TableBody实现保持同频滚动的方法
场景#xff1a;Header、Footer都有#xff0c;Table设置了scrollX#xff0c;才关注同频滚动
那么是如何实现的#xff1f;
监听onScroll方法获取到滚动条向左的滚动的距离scrollLeft#xff1b;同时给三个…
rc-table里Header、Footer、TableBody实现保持同频滚动的方法
场景Header、Footer都有Table设置了scrollX才关注同频滚动
那么是如何实现的
监听onScroll方法获取到滚动条向左的滚动的距离scrollLeft同时给三个dom设置scrollLeft
rc-table里的onScroll实现
先看一般的onScroll实现
监听onScroll获取scrollLeft设置header、footer、tableBody的scrollLeft 下面是伪代码哈
const onScroll (e: ScrollEvent) {// 拿到scrollLeftconst scrollLeft e.target.scrollLeft// 给所有的header、footer、table-body设置scrollLeftheader.scrollLeft scrollLeftfooter.scrollLeft scrollLefttableBody.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设置scrollLeftscrollHeaderRef.current mergedScrollLeft// body 设置scrollLeftscrollBodyRef.current mergedScrollLeft}};对比两个的实现可以看到rc-table里的实现多了一个入参scrollLeft和一个if判断 为什么多了一个入参、一个判断继续往下看
Header、Footer的滚动监听
用组件FixedHolder实现给FixedHolder绑定ref监听的是onWheel, 不是onScroll; 为什么监听onWheel不是onScroll?
React.useEffect(() {function onWheel(e: WheelEvent) {// deltaX: Returns a double representing the horizontal scroll amountconst { currentTarget, deltaX } e as unknown as React.WheelEventHTMLDivElement;// 避免触发不必要滚动 是一种优化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
divstyle{{overflow: hidden,...(isSticky ? { top: stickyTopOffset, bottom: stickyBottomOffset } : {}),}}ref{setScrollRef}className{classNames(className, {[stickyClassName]: !!stickyClassName,})}/tablestyle{{tableLayout: fixed,visibility: noData || mergedColumnWidth ? null : hidden,}}{(!noData || !maxContentScroll || allFlattenColumnsWithWidth) (ColGroupcolWidths{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;}, []);TableBody的滚动
当然是监听onScroll事件 给Tables设置scrollX的情况下TableBody设置样式{overflow-x: auto}这样会有同频滚动
divstyle{...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 useTimeoutLockState(defaultState?: State): [(state: State) void, () State | null] {const frameRef useRefState | null(defaultState || null);const timeoutRef useRefnumber();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
rc-table如何固定左右两侧
场景table的columns里设置fixed属性的时候会出现滚动fixed:true | left固定左侧fixed: right固定右侧
获取columns、columnWidths, 更新每个column的sticky的偏移距离更新涉及到fixed相关属性fixedLeft、fixedRight、lastFixLeft、firstFixRight、lastFixRight、firstFixLeft、isSticky
相关链接 rc-table: https://github.com/react-component/table antd-table: https://ant.design/components/table-cn#components-table-demo-fixed-columns