Обнаружение, когда пользователь прокручивает дно div с помощью React js

У меня есть сайт с разными разделами. Я использую 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);
  }
};

Ответ 1

Вы можете использовать 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);
  }
};

Ответ 2

Еще более простой способ сделать это с помощью scrollHeight, scrollTop и clientHeight.

Вычтите высоту прокрутки из общей высоты прокрутки. Если это равно видимой области, вы достигли дна!

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

Чтобы реагировать, просто добавьте прослушиватель 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 (не используя идентификаторы, игнорируя узлы DOM).

Вы также можете манипулировать уравнением, чтобы запускать страницу вверх (например, ленивая загрузка контента/бесконечная прокрутка).

Ответ 3

Мы также можем определить конец прокрутки 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);

Ответ 4

Я знаю, что на этот вопрос уже дан ответ, но, думаю, еще одно хорошее решение - это использовать то, что уже доступно в сообществе открытого исходного кода, вместо DIY. React Waypoints - это библиотека, которая существует для решения этой самой проблемы. (Хотя не спрашивайте меня, почему эта проблемная область определения того, прокручивает ли человек элемент HTML, называется "путевые точки", ха-ха)

Я думаю, что он очень хорошо спроектирован с контрактом на реквизит и определенно рекомендую вам проверить его.

Ответ 5

Расширяя ответ chandresh, чтобы использовать ответные хуки и реф, я бы сделал это так;

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

export default function Scrollable() {
    const [referenceNode, setReferenceNode] = useState();
    const [listItems] = useState(Array.from(Array(30).keys(), (n) => n + 1));

    useEffect(() => {
        return () => referenceNode.removeEventListener('scroll', handleScroll);
    }, []);

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

    const paneDidMount = (node) => {
        if (node) {
            node.addEventListener('scroll', handleScroll);
            setReferenceNode(node);
        }
    };

    return (
        <div
            ref={paneDidMount}
            style={{overflowY: 'scroll', maxHeight: '400px'}}
        >
            <ul>
                {listItems.map((listItem) => <li>List Item {listItem}</li>)}
            </ul>
        </div>
    );
}

Ответ 6

Добавьте следующие функции в свой React.Component, и все готово:]

  componentDidMount() {
    window.addEventListener("scroll", this.onScroll, false);
  }

  componentWillUnmount() {
    window.removeEventListener("scroll", this.onScroll, false);
  }

  onScroll = () => {
    if (this.hasReachedBottom()) {
      this.props.onScrollToBottom();
    }
  };

  hasReachedBottom() {
    return (
      document.body.offsetHeight + document.body.scrollTop ===
      document.body.scrollHeight
    );
  }