antd4里table滚动如何实现
首先antd4的table的底层实现是rc-table,就从rc-table来看看。
一、rc-table里Header、Footer、TableBody实现保持同频滚动的方法
场景:Table内容区域大于容器Table宽度,并且Table设置了scrollX,Header、Footer都有, 才关注同频滚动
那么是如何实现的?
监听onScroll方法获取到滚动条向左的滚动的距离scrollLeft;
同时给三个dom设置scrollLeft
二、 rc-table里的onScroll实现
先看一般的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判断;
为什么多了一个入参、一个判断?继续往下看?
三、 Header、Footer的滚动监听
用组件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;
// 避免触发不必要滚动, 是一种优化
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;