简体   繁体   English

如何使 div 滚动到其容器的底部,然后在 React 中完成后向上滚动?

[英]How to make a div scroll to the bottom of its container then scroll back up when it's done in React?

I've got multiple columns in a table that exceed the screen height while some do not, so I'm trying to get the overflowing columns to auto scroll down to show all data, then scroll back up, repeatedly.我有一个表格中的多列超过了屏幕高度,而有些则没有,所以我试图让溢出的列自动向下滚动以显示所有数据,然后向上滚动,重复。

I tried a recursive function like:我尝试了一个递归函数,如:

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);
  }

However I get the Maximum call stack size exceeded error for that.但是我得到了最大调用堆栈大小超出错误。 Works on non-React code, but not with React.适用于非 React 代码,但不适用于 React。

EDIT编辑

Full code.完整代码。

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;

It's just a one page table displaying info pulled in from an API.它只是一个一页表,显示从 API 中提取的信息。 Meant to be displayed on a TV screen, so trying to get anything that overflows to auto scroll.打算在电视屏幕上显示,所以试图让任何溢出的东西自动滚动。

Try to declare a variable in state that counts the amount of scrolls.尝试在state中声明一个计算滚动量的变量。 Then using this.setState() you can add one every time it the function is called.然后使用this.setState()您可以在每次调用该函数时添加一个。 If it is a multiple of 2 , then scroll down.如果它是 2 的倍数,则向下滚动。 Else scroll up.否则向上滚动。 To check if it is a multiple of 2, use % 2 .要检查它是否是 2 的倍数,请使用% 2

CSS approach CSS 方法

You can also do this without React.你也可以在没有 React 的情况下做到这一点。 When the user hovers over the non-overflowing columns, all of the columns will move downward.当用户将鼠标悬停在非溢出列上时,所有列都会向下移动。 Once the user gets his mouse out of the non-overflowing columns then the columns will move up.一旦用户将鼠标移出非溢出列,这些列就会向上移动。 I don't know if this is what you want or not.我不知道这是否是你想要的。

Hope this helps!希望这可以帮助!

It is probably better to make those scroll containers into React.Component's and move your scroll code there.最好将这些滚动容器放入 React.Component 并将滚动代码移到那里。 This way you only will the scroll code when the component is updated, which is whenever a child element is added and not need a setTimeout.这样你只会在组件更新时滚动代码,这是在添加子元素并且不需要 setTimeout 时。 Here is what that would look like:这就是它的样子:

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>
    )
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM