欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 房产 > 建筑 > Table 滚动条始终停靠在可视区域的底部

Table 滚动条始终停靠在可视区域的底部

2024/11/29 18:41:00 来源:https://blog.csdn.net/weixin_52648900/article/details/144051951  浏览:    关键词:Table 滚动条始终停靠在可视区域的底部

1. 话题引入

存在这样一个场景:当页面尺寸发生变化时,希望滚动条能够随之动态调整,始终展示在 table 的可视区域的最下方,而不是整个 table 本身的最底部。

这种行为可以提升用户的使用体验,尤其是在处理大数据表格时,用户不需要滚动到整个页面的最底部才能看到滚动条,而是始终在当前可视区域操作。

效果如下,在 Table 未完全展示下的滚动条:

完全展示后,滚动条在 右侧 和 底部。

2. 如何实现?

这个实现方法比较困难,不能通过控制 Table 自带的滚动条或简单的 CSS 来实现效果。我尝试了很久,都不OK,因此决定手动实现一个与其本身风格一致的自定义滚动条。

需要解决的问题包括:

1、监听横向滚动条,实时捕获水平滚动状态并动态更新滚动条的位置和宽度。样式部分可以简单处理,不是重点。

2、监听视口可视区域高度变化,动态展示滚动条,使用 position 固定到可视区域底部。

3、实现拖拽滚动功能,通过鼠标按下滚动条并拖动,能够实现同步滚动的效果。

3. 解决实现

感兴趣的小伙伴可以自行实现下哦O。

HTML 结构

在 Table 下使用一个 div 实现滚动条效果,📢 外层的 div 是必须的,负责实时的定位效果。

<div class="custom-container" style={{ position: "relative" }}><ElTable ref={tableRef} {...props} {...attrs} v-slots={slots}>{slots.default && slots.default()}</ElTable><divclass="custom-scrollbar"style={{zIndex: 999,width: `${scrollBarWidthRef.value}px`,height: `${SCROLLBAR_HEIGHT}px`,position: "absolute",top: `${scrollBarTopRef.value}px`,left: `${scrollBarLeftRef.value}px`}}onMousedown={onMouseDown}></div>
</div>

第一个问题:滚动条宽度和位置处理

难点:监听横向滚动条变化

const getScrollBarWidth = () => {// 获取横向滚动条元素const scrollWrapper = tableRef.value?.$el.querySelector(".el-scrollbar__wrap");// 获取 table 元素大小及其相对位置const tableRect = tableRef.value?.$el.getBoundingClientRect();// ---- 获取滚动条的宽度(源码) ----const GAP = 4;const offsetWidth = scrollWrapper.offsetWidth - GAP;const originalWidth = offsetWidth ** 2 / scrollWrapper.scrollWidth;const scrollbarWidth = Math.max(originalWidth, SCROLLBAR_MIN_WIDTH);scrollBarWidthRef.value = scrollbarWidth;return {tableRect, // 表格大小scrollbarWidth // 滚动条宽度};
};

接下来设置滚动条的位置

// 设置滚动条宽度
const setScrollBarWidth = () => {const { scrollbarWidth } = getScrollBarWidth();scrollBarWidthRef.value = scrollbarWidth;
};// 设置滚动条高度
const setScrollBarTop = () => {const { tableRect } = getScrollBarWidth();scrollBarTopRef.value =window.innerHeight - tableRect.top - SCROLLBAR_HEIGHT > tableRect.height? tableRect.height - SCROLLBAR_HEIGHT: window.innerHeight - tableRect.top - SCROLLBAR_HEIGHT;
};// 监听滚动的同时设置 Left
const handleScroll = e => {const { tableRect } = getScrollBarWidth();setScrollBarTop();setScrollBarWidth();if (e.target) {// 比例计算scrollBarLeftRef.value = (e.target.scrollLeft / e.target.scrollWidth) * tableRect.width;}
};const handleWindowScroll = () => {setScrollBarTop();
};

既然方法都写好啦,那就开始调用。

onMounted(() => {// 初始化时执行// 为什么在 setTimeout 呢?避免过早地执行这些方法,它们依赖于表格 DOM 完全渲染完成后的尺寸信息。setTimeout(() => {setScrollBarWidth();setScrollBarTop();}, 0);// 确保 DOM 已完全更新nextTick(() => {if (tableRef.value) {scrollWrapperRef.value = tableRef.value?.$el.querySelector(".el-scrollbar__wrap");bodyWrapperRef.value = tableRef.value?.$el.querySelector(".el-table__body-wrapper");if (scrollWrapperRef.value) {scrollWrapperRef.value.addEventListener("scroll", handleScroll);}if (bodyWrapperRef.value) {window.addEventListener("scroll", handleWindowScroll);}}});
});

注意:当窗口尺寸变化时,需要重新计算滚动条的高度和宽度。

const handleResize = () => {setScrollBarWidth();setScrollBarTop();
};
window.addEventListener("resize", handleResize);

OK,到此滚动条的位置完成,接下来处理滚动条的拖拽。

这个就比较简单了,监听鼠标抬起,移动的事件,设置滚动距离。

let isDragging = false;
let startX = 0;
let startLeft = 0;
let rafId: number | null = null;// 鼠标抬起
const onMouseUp = () => {isDragging = false;document.removeEventListener("mousemove", onMouseMove);document.removeEventListener("mouseup", onMouseUp);
};
// 鼠标移动
const onMouseMove = (e: MouseEvent) => {if (!isDragging) return;if (rafId !== null) {cancelAnimationFrame(rafId);}rafId = requestAnimationFrame(() => {const moveX = e.clientX - startX; // 计算拖动距离const newLeft = startLeft + moveX; // 计算滚动条的新位置scrollBarLeftRef.value = Math.max(0,Math.min(newLeft, tableRef.value?.$el.scrollWidth - scrollBarWidthRef.value));// 更新表格滚动位置if (scrollWrapperRef.value) {scrollWrapperRef.value.scrollLeft = (scrollBarLeftRef.value / tableRef.value?.$el.scrollWidth) * scrollWrapperRef.value.scrollWidth;}});
};
// 鼠标按下
const onMouseDown = (e: MouseEvent) => {isDragging = true;startX = e.clientX;startLeft = scrollBarLeftRef.value; // 当前滚动条的位置document.addEventListener("mousemove", onMouseMove);document.addEventListener("mouseup", onMouseUp);
};

按下滚动条可滑动 Table。

最后清空一下监听的事件。

onBeforeUnmount(() => {if (scrollWrapperRef.value) {scrollWrapperRef.value.removeEventListener("scroll", handleScroll);}window.removeEventListener("scroll", handleWindowScroll);window.removeEventListener("resize", handleResize);
});

自此就成功实现一个符合要求的滚动条 👏🏻 👏🏻 👏🏻。 

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com