React实现自动滚动列表

用React实现了一个自动滚动的内容区域,先上图图:


1.用处:

用于实现列表的自动滚动,鼠标进入可停止滚动

2.实现原理:

创建一个dom为ul,赋值为列表,然后拷贝这个dom赋值给第二个ul,然后判断屏幕高度跟滚动高度对比,利用requestAnimationFrame动画实现滚动

3.注意事项:

可在render里传需要渲染的表格,比如状态这一栏文字前面加个小圆圈等等,可以在render中传入,如果需要传任意内容,可修改ul里的内容,改为children由父组件传入

代码:

import React, { ReactNode } from 'react';
import style from './style/index.less';

interface ViewState {}

interface ViewProps {
  height: number;
  dataSource: Record<string, any>[];
  columns: TableColumn[];
  headerHeight?: number;
  rowHeight?: number;
  onRowClick?: (l: Record<string, any>) => void;
  rowKey?: string;
  scroll?: boolean;
}

export interface TableColumn {
  key: string;
  title: string;
  width: number;
  render?: (index: number, data: Record<string, any>, text: any) => string | ReactNode;
  onClick?: (data: Record<string, any>) => void;
}

export default class ScrollTable extends React.Component<ViewProps, ViewState> {
  private wrapperDom = React.createRef<any>();
  private childDom1 = React.createRef<any>();
  private childDom2 = React.createRef<any>();
  private count = 0;
  private reqAnimation: number;

  public componentDidMount = () => {
    this.reqAnimation = window.requestAnimationFrame(this.taskStart);
  };
  public componentWillUnmount = () => {
    this.handleEnter();
  };

  public render() {
    const { height, dataSource, columns, rowHeight = 27.5, headerHeight = 36, rowKey } = this.props;
    return (
      <div className={style.scrollContainer} style={{ height: `${height / 100}rem` }}>
        <div className={style.scrollHead}>
          {columns.map(l => (
            <div key={l.key} style={{ width: `${l.width / 100}rem` }}>
              {l.title}
            </div>
          ))}
        </div>
        <div
          className={style.scrollBody}
          ref={this.wrapperDom}
          style={{ height: `${(height - headerHeight) / 100}rem` }}
        >
          <ul ref={this.childDom1} onMouseOver={this.handleEnter} onMouseLeave={this.handleLeave}>
            {dataSource.map((l, i) => (
              <li
                data-key={rowKey ? l[rowKey] : `list${i}`}
                key={rowKey ? l[rowKey] : `list${i}`}
                style={{ height: `${rowHeight / 100}rem` }}
              >
                {columns.map((p, c) => {
                  let pStyle: Record<string, any> = { width: `${p.width / 100}rem` };
                  if (l.lineColor) {
                    pStyle['color'] = l.lineColor;
                  }
                  return (
                    <div
                      key={`p${c}`}
                      style={pStyle}
                      onClick={e => {
                        e.stopPropagation();
                        this.onCellClick(l, p);
                        this.props.onRowClick?.(l);
                      }}
                    >
                      {p?.render?.(i, l, l[p.key]) || l[p.key]}
                    </div>
                  );
                })}
              </li>
            ))}
          </ul>
          <ul ref={this.childDom2} />
        </div>
      </div>
    );
  }

  private taskStart = () => {
    if (
      this.childDom1.current?.clientHeight >= this.wrapperDom.current?.clientHeight &&
      this.childDom2.current?.clientHeight < 10
    ) {
      this.childDom2.current.innerHTML = this.childDom1.current.innerHTML;
    }
    if (this.wrapperDom.current.scrollTop >= this.childDom1.current.scrollHeight) {
      this.wrapperDom.current.scrollTop = 0;
      this.count = 0;
    } else {
      this.count += 1;
      this.wrapperDom.current.scrollTop = this.count;
    }
    if (this.props.scroll) {
      this.reqAnimation = window.requestAnimationFrame(this.taskStart);
    }
  };

  private handleEnter = () => {
    window.cancelAnimationFrame(this.reqAnimation);
  };
  private handleLeave = () => {
    this.reqAnimation = window.requestAnimationFrame(this.taskStart);
  };
  private onCellClick = (l: Record<string, any>, p: TableColumn) => {
    p?.onClick?.(l);
  };
}

样式文件:

.scrollContainer {
  width: 100%;

  div {
    text-align: center;
    display: inline-block;
    margin: 0;
    font-size: 14px;
    font-weight: normal;
    font-stretch: normal;
    letter-spacing: 0;
    opacity: 0.9;
  }

  .scrollHead {
    display: flex;
    height: 42px;
    align-items: center;
    background-color: rgba(0, 183, 185, 0.3);

    div {
      font-size: 14px;
      font-stretch: normal;
      letter-spacing: 0;
      color: #07d8b5;
      font-family: MicrosoftYaHei, sans-serif;
      opacity: 1;
    }
  }

  .scrollBody {
    overflow-y: scroll;
    width: 100%;
    scrollbar-width: none;
    -ms-overflow-style: none;

    ul {
      height: auto;
      padding: 0;
      margin: 0;
    }

    li {
      list-style: none;
      position: relative;
      cursor: pointer;
      display: flex;
      height: 36px;
      color: #fff;
      align-items: center;
    }

    li div {
      line-height: 36px;
      color: #fff;
      white-space: nowrap; /* 文本不换行 */
      overflow: hidden; /* 溢出部分隐藏 */
      text-overflow: ellipsis; /* 溢出部分用"..."代替 */
    }

    li:hover {
      background: rgba(43, 143, 171, 0.52);
      > div {
        color: #fff;
      }
    }

    &::-webkit-scrollbar {
      display: none;
    }

    li:nth-child(even) {
      background-color: rgba(43, 143, 171, 0.13);
    }

    li:nth-child(even):hover {
      background: rgba(43, 143, 171, 0.52);
      color: #fff;
    }
  }
}

  • 17
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
实现自动滚动的虚拟长列表,可以使用 React 的 `react-window` 库。这个库提供了一些组件来优化大型列表的性能,其中包括 `FixedSizeList` 和 `VariableSizeList` 组件。这两个组件都支持自动滚动。 下面是一个使用 `FixedSizeList` 组件实现自动滚动的示例: ```jsx import React, { useRef, useEffect } from 'react'; import { FixedSizeList } from 'react-window'; function VirtualList({ itemCount, itemSize, height }) { const listRef = useRef(null); useEffect(() => { if (listRef.current) { // 自动滚动到底部 listRef.current.scrollToItem(itemCount - 1); } }, [itemCount]); const renderRow = ({ index, style }) => { return ( <div style={style}> Row {index} </div> ); }; return ( <FixedSizeList ref={listRef} itemCount={itemCount} itemSize={itemSize} height={height} width="100%" > {renderRow} </FixedSizeList> ); } export default VirtualList; ``` 在这个组件中,我们使用了 `useRef` 钩子来获取 `FixedSizeList` 组件的引用,然后在 `useEffect` 钩子中调用 `scrollToItem` 方法来自动滚动列表的底部。`scrollToItem` 方法接收一个索引值作为参数,它会将该索引所对应的滚动到可视区域内。 你可以将 `itemCount`、`itemSize` 和 `height` 作为 props 传递给 `VirtualList` 组件,它们分别表示列表数、每的高度和列表的高度。在 `renderRow` 函数中,我们根据索引值渲染每一的内容。 这个组件可以像下面这样使用: ```jsx function App() { return ( <div> <h1>Virtual List</h1> <VirtualList itemCount={1000} itemSize={50} height={500} /> </div> ); } export default App; ``` 在这个示例中,我们创建了一个包含 1000 的虚拟列表,每的高度为 50 像素,列表的高度为 500 像素。当组件挂载时,它会自动滚动列表的底部。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值