页面滚动时如何让Material Table水平滚动条始终可见?
React 配合 Material Table 实现常驻水平滚动条(无jQuery依赖)
不需要引入依赖jQuery的floatingScroll插件,通过原生DOM事件绑定+React状态控制就能实现相同效果,核心是做一个和原表格滚动位置双向同步的悬浮滚动条,在页面滚动到对应区间时固定在视口底部显示。
实现逻辑
- 分别获取Material Table内部原生滚动容器、自定义悬浮滚动条的DOM引用,做双向滚动绑定,保证两者横向滚动位置完全同步
- 监听页面滚动事件,实时计算表格在视口中的位置,判断是否需要显示悬浮滚动条
- 监听窗口大小变化、表格数据/列配置更新事件,动态校准悬浮滚动条的可滚动宽度,保证滚动比例和原生表格完全一致
- 悬浮滚动条固定在视口底部时设置足够高的层级,避免被其他页面元素遮挡
可直接复用的实现代码
import React, { useRef, useEffect, useState } from 'react'; import MaterialTable from 'material-table'; export default function TableWithStickyScroll() { const tableWrapperRef = useRef(null); const floatingScrollRef = useRef(null); const [floatingScrollVisible, setFloatingScrollVisible] = useState(false); const [scrollContentWidth, setScrollContentWidth] = useState(0); useEffect(() => { if (!tableWrapperRef.current) return; // 拿到Material Table内置的滚动容器 const nativeScrollContainer = tableWrapperRef.current.querySelector('.MuiTableContainer-root'); if (!nativeScrollContainer || !floatingScrollRef.current) return; // 初始化滚动区域宽度 const updateScrollWidth = () => { setScrollContentWidth(nativeScrollContainer.scrollWidth); }; updateScrollWidth(); // 双向同步滚动位置 const syncNativeScroll = () => { floatingScrollRef.current.scrollLeft = nativeScrollContainer.scrollLeft; }; const syncFloatingScroll = () => { nativeScrollContainer.scrollLeft = floatingScrollRef.current.scrollLeft; }; nativeScrollContainer.addEventListener('scroll', syncNativeScroll); floatingScrollRef.current.addEventListener('scroll', syncFloatingScroll); // 页面滚动时控制悬浮条显隐 const handlePageScroll = () => { const containerRect = nativeScrollContainer.getBoundingClientRect(); // 表格部分滚出视口顶部、且还未完全滚出视口底部时显示悬浮条 const shouldShow = containerRect.top < 0 && containerRect.bottom > 30; setFloatingScrollVisible(shouldShow); }; // 窗口大小变化时重新计算宽度 const handleResize = () => { updateScrollWidth(); handlePageScroll(); }; window.addEventListener('scroll', handlePageScroll); window.addEventListener('resize', handleResize); return () => { nativeScrollContainer.removeEventListener('scroll', syncNativeScroll); floatingScrollRef.current.removeEventListener('scroll', syncFloatingScroll); window.removeEventListener('scroll', handlePageScroll); window.removeEventListener('resize', handleResize); }; }, []); return ( <div ref={tableWrapperRef} style={{ position: 'relative' }}> <MaterialTable // 此处替换为业务侧的表格配置,包括列定义、数据、操作项等 title="业务表格" columns={[]} data={[]} /> {/* 悬浮水平滚动条 */} {floatingScrollVisible && ( <div ref={floatingScrollRef} style={{ position: 'fixed', bottom: 0, left: 0, width: '100%', height: 20, overflowX: 'auto', overflowY: 'hidden', zIndex: 999, background: '#ffffff', boxShadow: '0 -2px 6px rgba(0,0,0,0.08)' }} > <div style={{ width: scrollContentWidth, height: 1 }} /> </div> )} </div> ); }
适配注意事项
- 如果项目有固定在底部的导航栏/操作栏,可以调整悬浮滚动条的
bottom值,避免和固定元素重叠 - 如果表格存在动态列显隐、滚动加载数据、列宽拖拽调整的场景,要在对应操作完成后调用宽度更新逻辑,保证悬浮滚动条的滚动比例准确
- 可以根据项目的UI风格调整悬浮滚动条的背景、阴影样式,和整体设计风格保持统一
- 整个实现不需要引入任何jQuery相关依赖,打包体积远小于直接引入floatingScroll插件
内容的提问来源于stack exchange,提问作者Martin TT
相关产品推荐
相关产品推荐

