首页 > 解决方案 > 如何使 div 滚动到其容器的底部,然后在 React 中完成后向上滚动?

问题描述

我的表格中有多个列超过了屏幕高度,而有些则没有,所以我试图让溢出的列自动向下滚动以显示所有数据,然后反复向上滚动。

我尝试了一个递归函数,例如:

function colScroll() {
    let el = document.getElementById("col");
    if (el.scrollHeight - el.scrollTop === el.clientHeight) {
      el.scrollBy(0,-1);
    } else {
      el.scrollBy(0,1);
    }
    let scrolldelay = setTimeout(colScroll,10);
  }

但是,我得到了超出最大调用堆栈大小的错误。适用于非 React 代码,但不适用于 React。

编辑

完整的代码。

import React from 'react';
import axios from 'axios';
import DataCard from './DataCard';
import 'bootstrap/dist/css/bootstrap.min.css';
import './app.scss';

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: []
    }

    this.scrollColumn = this.scrollColumn.bind(this);
  }

  scrollColumn() {
    let el = document.getElementById("col-pending-auth");
    if (el.scrollHeight - el.scrollTop === el.clientHeight) {
      el.scrollBy(0,-1);
    } else {
      el.scrollBy(0,1);
    }
    scrolldelay = setTimeout(scrollColumn, 10);
  }

  componentDidMount() {
    const url = new URL("example.com");
    const params = {};
    url.search = new URLSearchParams(params).toString();

    axios.get(url)
      .then(res => {
        this.setState({data: res.data});
        console.log(res.data);
      });

      this.scrollColumn();
  }

  render() {
    return(
      <div className="table-responsive">
        <table className="table">
        <thead>
          <tr>
          <th scope="col">Proposed</th>
          <th scope="col">Pending Auth</th>
          <th scope="col">Rejected</th>
          <th scope="col">Approved</th>
          <th scope="col">Pending Review</th>
          <th scope="col">Plant Reviewed</th>
          </tr>
        </thead>
        <tbody>
          <tr>
            <td>
              <div className="scroll-container" id="col-proposed">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "0") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
            <td>
              <div className="scroll-container" id="col-pending-auth">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "1") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
            <td>
              <div className="scroll-container" id="col-rejected">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "3") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
            <td>
              <div className="scroll-container" id="col-approved">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "2") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
            <td>
              <div className="scroll-container" id="col-pending-review">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "5") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
            <td>
              <div className="scroll-container" id="col-plant-reviewed">
                {
                  this.state.data.map((item, idx) => {
                    if (item.ID === "4") {
                      return <DataCard cardData={item} key={idx} />
                    }
                  })
                }
              </div>
            </td>
          </tr>
        </tbody>
        </table>
      </div>
    )
  }
}


export default App;

它只是一个单页表,显示从 API 中提取的信息。旨在显示在电视屏幕上,因此试图让任何溢出的内容自动滚动。

标签: javascriptreactjs

解决方案


将这些滚动容器放入 React.Component 并将滚动代码移到那里可能会更好。这样,您只会在组件更新时滚动代码,即每当添加子元素并且不需要 setTimeout 时。这就是它的样子:

import React, { Component, useRef, useLayoutEffect } from 'react';

const ScrollColumn = ({children}) => {
  const scroller = useRef(null)
  const scrollColumn = () => {
    let el = scroller.current;
    if (!el) return

    if (el.scrollHeight - el.scrollTop === el.clientHeight) {
      el.scrollBy(0, -1);
    } else {
      el.scrollBy(0,1);
    }
  }

  useLayoutEffect(scrollColumn)

  return <div ref={scroller} className='scroll-container'>{children}</div>
}

class App extends React.Component {
  state = {
    data: []
  }

  componentDidMount() {

    axios.get('/data.json').then( res => {
      console.log(res)
      this.setState({data: res.data}) 
    })

  }

  render() {
    return(
      <div className="table-responsive">
        <ScrollColumn>
          {
            this.state.data.map((item) => (
              <DataCard cardData={item} key={item.id} />
            ))
          }
        </ScrollColumn>
      </div>
    )
  }
}

推荐阅读