使用 React js 检测用户何时滚动到 div 的底部

IT技术 javascript reactjs
2021-01-19 14:49:33

我有一个包含不同部分的网站。我正在使用 segment.io 来跟踪页面上的不同操作。如何检测用户是否已滚动到 div 的底部?我尝试了以下操作,但似乎在我滚动页面时触发,而不是在我到达 div 底部时触发。

componentDidMount() {
  document.addEventListener('scroll', this.trackScrolling);
}

trackScrolling = () => {
  const wrappedElement = document.getElementById('header');
  if (wrappedElement.scrollHeight - wrappedElement.scrollTop === wrappedElement.clientHeight) {
    console.log('header bottom reached');
    document.removeEventListener('scroll', this.trackScrolling);
  }
};
6个回答

一种更简单的方法是使用scrollHeightscrollTopclientHeight

从总可滚动高度中减去滚动高度。如果这等于可见区域,则您已到达底部!

element.scrollHeight - element.scrollTop === element.clientHeight

在 React 中,只需在可滚动元素上添加一个 onScroll 侦听器,并event.target在回调中使用

class Scrollable extends Component {

  handleScroll = (e) => {
    const bottom = e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
    if (bottom) { ... }
  }

  render() {
    return (
      <ScrollableElement onScroll={this.handleScroll}>
        <OverflowingContent />
      </ScrollableElement>
    );
  }
}

我发现这更直观,因为它处理可滚动元素本身,而不是window,并且它遵循正常的 React 做事方式(不使用 id,忽略 DOM 节点)。

您还可以操纵方程式以在页面上方触发(例如,延迟加载内容/无限滚动)。

谢谢!你帮了我很多。比事件监听器更好的解决方案!
2021-03-16 14:49:33
很棒的解决方案!为我省去了很多麻烦!谢谢
2021-03-22 14:49:33
来自scrollTop网络文档: On systems using display scaling, scrollTop may give you a decimal value. 如果您想考虑浏览器窗口中不同级别的缩放,您可能需要使用 scrollTop 的上限来比较这些值。 node.scrollHeight - Math.ceil(node.scrollTop) === node.clientHeight
2021-03-23 14:49:33
怎么样Math.abs(scrollHeight - (scrollTop + clientHeight) <= 1到目前为止对我来说效果很好。
2021-03-31 14:49:33
出于某种原因,我的scrollTop结果是“低”十进制值。例如 34.22233。出于这个原因,我使用Math.floor(scrollTop). 这似乎有点“hacky”。我会找到应该实施 ceil 而不是 floor 的情况吗?有更好的解决方案吗?也许Math.Round
2021-04-08 14:49:33

您可以使用el.getBoundingClientRect().bottom检查底部是否已被查看

isBottom(el) {
  return el.getBoundingClientRect().bottom <= window.innerHeight;
}

componentDidMount() {
  document.addEventListener('scroll', this.trackScrolling);
}

componentWillUnmount() {
  document.removeEventListener('scroll', this.trackScrolling);
}

trackScrolling = () => {
  const wrappedElement = document.getElementById('header');
  if (this.isBottom(wrappedElement)) {
    console.log('header bottom reached');
    document.removeEventListener('scroll', this.trackScrolling);
  }
};
document.removeEventListener在组件卸载 ( componentWillUnmount) 时删除事件 ( )也是一个好习惯
2021-03-15 14:49:33
@StavAlfi 因为你可能没有“标题”ID
2021-03-29 14:49:33
wrappedElement一片空白。为什么?
2021-04-05 14:49:33

这是使用 React Hooks 和 ES6 的解决方案:

import React, { useRef, useEffect } from 'react';

const MyListComponent = () => {
  const listInnerRef = useRef();

  const onScroll = () => {
    if (listInnerRef.current) {
      const { scrollTop, scrollHeight, clientHeight } = listInnerRef.current;
      if (scrollTop + clientHeight === scrollHeight) {
        // TO SOMETHING HERE
        console.log('Reached bottom')
      }
    }
  };

  return (
    <div className="list">
      <div className="list-inner" onScroll={() => onScroll()} ref={listInnerRef}>
        {/* List items */}
      </div>
    </div>
  );
};

export default List;

我们还可以通过使用 ref 来检测 div 的滚动结束。

import React, { Component } from 'react';
import {withRouter} from 'react-router-dom';
import styles from 'style.scss';

class Gallery extends Component{ 

  paneDidMount = (node) => {    
    if(node) {      
      node.addEventListener("scroll", this.handleScroll.bind(this));      
    }
  }

  handleScroll = (event) => {    
    var node = event.target;
    const bottom = node.scrollHeight - node.scrollTop === node.clientHeight;
    if (bottom) {      
      console.log("BOTTOM REACHED:",bottom); 
    }    
  }

  render() {
    var that = this;        
    return(<div className={styles.gallery}>
      <div ref={that.paneDidMount} className={styles.galleryContainer}>
        ...
      </div>

    </div>);   
  }
}

export default withRouter(Gallery);

这个答案属于 Brendan,让我们让它发挥作用

export default () => {
   const handleScroll = (e) => {
       const bottom = e.target.scrollHeight - e.target.scrollTop === e.target.clientHeight;
       if (bottom) { 
           console.log("bottom")
       }
    }

  return (
     <div onScroll={handleScroll}  style={{overflowY: 'scroll', maxHeight: '400px'}}  >
        //overflowing elements here
   </div>
  )
}

如果第一个 div 不可滚动,它将不起作用,并且 onScroll 在第一个 div 之后的 div 等子元素中对我不起作用,因此 onScroll 应该位于第一个溢出的 HTML 标记处