基于React实现无限滚动表格

 更新时间:2023年11月10日 08:36:14   作者:寄给江南  
以文本为例,为了实现无限循环的视觉效果,我们需要准备两段相同的文本,并让第二段文本的头部衔接在第一段文本的尾部,同时,为两段文本设置相同的滚动动画,本文给大家介绍了基于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 变量,通过 onMouseEnteronMouseLeave 事件改变 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无限滚动表格的资料请关注脚本之家其它相关文章!

您可能感兴趣的文章:

相关文章

  • React Native中导航组件react-navigation跨tab路由处理详解

    React Native中导航组件react-navigation跨tab路由处理详解

    这篇文章主要给大家介绍了关于React Native中导航组件react-navigation跨tab路由处理的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2017-10-10
  • 从闭包陷阱到内存泄漏解析React Hooks避坑指南

    从闭包陷阱到内存泄漏解析React Hooks避坑指南

    这篇文中主要从闭包陷阱到依赖地狱,从无限循环到内存泄漏,为大家简单盘点一下React Hooks中的常见避坑方法,文中的示例代码讲解详细,希望对大家有所帮助
    2026-03-03
  • React闭包陷阱产生和解决小结

    React闭包陷阱产生和解决小结

    闭包陷阱是一个常见的问题,尤其是在处理异步操作、事件处理器、或是定时器时,本文就来介绍一下React闭包陷阱产生和解决小结,具有一定的参考价值,感兴趣的可以了解一下
    2025-04-04
  • ios原生和react-native各种交互的示例代码

    ios原生和react-native各种交互的示例代码

    本篇文章主要介绍了ios原生和react-native各种交互的示例代码,非常具有实用价值,需要的朋友可以参考下
    2017-08-08
  • react+react-beautiful-dnd实现代办事项思路详解

    react+react-beautiful-dnd实现代办事项思路详解

    这篇文章主要介绍了react+react-beautiful-dnd实现代办事项,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-06-06
  • React Refs 的使用forwardRef 源码示例解析

    React Refs 的使用forwardRef 源码示例解析

    这篇文章主要为大家介绍了React 之 Refs 的使用和 forwardRef 的源码解读,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-11-11
  • React实现父子组件有效通信的多种方式

    React实现父子组件有效通信的多种方式

    在React中,父子组件之间的通信是一个重要的概念,它直接影响到数据传递和组件的交互,了解如何实现父子组件之间的有效通信,可以帮助你构建更高效、可维护的应用,本文将详细探讨父子组件通信的多种方式,包括属性传递、回调函数、上下文API、以及更高级的状态管理解决方案,
    2025-07-07
  • ReactNative页面跳转实例代码

    ReactNative页面跳转实例代码

    这篇文章主要介绍了ReactNative页面跳转的代码,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-09-09
  • React-router v4 路由配置方法小结

    React-router v4 路由配置方法小结

    本篇文章主要介绍了React-router v4 路由配置方法小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-08-08
  • React组件三大核心属性State props Refs介绍

    React组件三大核心属性State props Refs介绍

    组件实例的三大核心属性是:State、Props、Refs。类组件中这三大属性都存在。函数式组件中访问不到 this,也就不存在组件实例这种说法,但由于它的特殊性(函数可以接收参数),所以存在Props这种属性
    2023-02-02

最新评论