基于React实现无限滚动表格
作者:寄给江南
无限滚动效果
以文本为例,为了实现无限循环的视觉效果,我们需要准备两段相同的文本,并让第二段文本的头部衔接在第一段文本的尾部。同时,为两段文本设置相同的滚动动画。
当第一段文本滚动到尾部时,如果能让第一段文本的位置瞬间移动回头部,并将第一段文本的头部内容替换为第二段的头部内容,同时动画也回到开始位置,这样,用户从视觉效果上看是感受不到变化的。
以下代码是 Marquee
组件及其样式的简单实现。
// Marquee.tsx export default function Marquee(props) { const { children } = props; return ( <div className={styles.marquee}> <div className={styles.ctx}>{children}</div> <div className={styles.ctx}>{children}</div> </div> ); } // App.tsx export default function App() { return ( <Marquee>只期待 後來的你 能快樂 那就是 後來的我 最想的</Marquee> ); }
// Marquee.module.scss .marquee { width: 40px; overflow: hidden; position: relative; .ctx { animation: scroll 4s infinite linear; // 指定滚动动画 } } @keyframes scroll { 0% { transform: translateY(0); } 100% { transform: translateY(-100%); } }
悬停效果
实现鼠标悬停效果,通常有两种方法:
- 声明
isHovered
变量,通过onMouseEnter
和onMouseLeave
事件改变isHovered
的值,从而实现悬停效果。 - 使用
:hover
伪类,通过设置animation-play-state
属性控制动画的运行,从而实现悬停效果。
本文使用第二种方法,为整个外层容器设置 :hover
样式。当鼠标悬浮在整个容器上时,让内部元素的动画暂停。我们在 Marquee.module.scss
文件中添加如下样式:
// ... .marquee:hover { .ctx { animation-play-state: paused; } }
到此,最基本的功能已经实现,接下来开始实现表格组件的无限滚动。
表格的无限滚动
首先,实现根据配置动态生成表格的功能。我们从传入的对象数组中提取所有的键,作为表头内容。
本文实现的表头提取函数考虑了传入可选参数的情况,因此它会遍历所有列表项并提取所有存在的键。如果表头属性是固定数量的话,可以使用更简便的方法来提取键。
提取出表头后,我们就可以遍历对象数组中的每一项,并根据对应的键将属性值填入相应的单元格中,逐步构建起表格内容。
基于上述步骤分析,表格组件的初步实现如下(样式在文章末尾给出):
// DataTable.tsx export default function DataTable<T extends object>({ dataSource }: { dataSource: Array<T> }) { if (!Array.isArray(dataSource) || dataSource.length === 0) { return null; // 数据源不是数组或数组为空,停止操作 } const labelList = dataSource.reduce((acc: any, cur: any) => { const keys = Object.keys(cur); for (const key of keys) { if (!acc.includes(key)) { acc.push(key); } } return acc; }, []); // 提取表头 return ( <table> <thead> <tr> {labelList.map((key, index) => ( <th key={index}>{key}</th> ))} </tr> </thead> <tbody> {dataSource.map((data, rowIndex) => ( <tr key={rowIndex}> {labelList.map((key, columnIndex) => ( <!-- 如果是可选属性,赋予默认值 --> <td key={columnIndex}>{data[key] ?? '-'}</td> ))} </tr> ))} </tbody> </table> ); }
此时,在 App.tsx
中直接引用 DataTable
组件并传入 data
数组,就可以看到表格动态生成如下。
// App.tsx import DataTable from '@/components/DataTable'; export default function App() { const data = [ { name: 'Alice', city: 'New York' }, { name: 'Bob', age: 30, city: 'San Francisco' }, { name: 'Charlie', age: 35, city: 'Chicago' }, { name: 'David', age: 40, city: 'Los Angeles', num: 0 }, ]; return ( <DataTable dataSource={data} /> ); }
接下来,就是加上无限滚动的效果。
通常来说,可滚动表格只会有一个表头,也就是只有一个 thead
部分,并且此处我们把它固定在顶部。再按照上述文字滚动的实现思路,我们只要在一个 table
中准备两份相同的 tbody
内容,然后给这两份 tbody
设置相同的动画即可。
同时,为了限制整体容器的高度,以防用户在表格位置滚动时感知到突变,造成不好的视觉体验,还需要给 table
加一层外部容器。
到此,整个分析过程就结束了,DataTable
组件的最终实现如下:
// DataTable.tsx export default function DataTable<T extends object>({ dataSource }: { dataSource: Array<T> }) { if (!Array.isArray(dataSource) || dataSource.length === 0) { return null; // 数据源不是数组或数组为空,停止操作 } const labelList = dataSource.reduce((acc: any, cur: any) => { const keys = Object.keys(cur); for (const key of keys) { if (!acc.includes(key)) { acc.push(key); } } return acc; }, []); // 提取表头 return ( <div className={styles.container}> <table className={styles.table}> <thead> <tr> {labelList.map((key, index) => ( <th key={index}>{key}</th> ))} </tr> </thead> <tbody className={styles.tbody}> {dataSource.map((data, rowIndex) => ( <tr key={rowIndex}> {labelList.map((key, columnIndex) => ( <td key={columnIndex}>{data[key] ?? '-'}</td> ))} </tr> ))} </tbody> <tbody className={styles.tbody}> {dataSource.map((data, rowIndex) => ( <tr key={rowIndex}> {labelList.map((key, columnIndex) => ( <td key={columnIndex}>{data[key] ?? '-'}</td> ))} </tr> ))} </tbody> </table> </div> ); }
// DataTable.module.scss @keyframes scroll { 0% { transform: translateY(0); } 100% { transform: translateY(-100%); } } .container { height: 160px; overflow: hidden; .table { height: 100%; overflow: hidden; position: relative; background-color: #e6e6e6; .tbody { animation: scroll 4s infinite linear; } } } table { width: max-content; border-spacing: 0; thead { height: 30px; z-index: 99; background-color: #adbcaa; position: sticky; top: 0; tr { color: #fff; font-weight: bold; } } th, td { width: max-content; padding: 0 8px; line-height: 30px; text-align: center; } }
然后,刷新页面,再看一下页面效果,这样就实现了。
最后
以上就是基于React实现无限滚动表格的详细内容,更多关于React无限滚动表格的资料请关注脚本之家其它相关文章!