react-scrollload

import React from 'react';
import { findDOMNode } from 'react-dom';
import throttle from 'lodash/throttle';
import { Spin } from '@wind/wind-ui';
import ReactPlaceHolder from 'react-placeholder';
/**
 * 需找当前元素最近可滚动的父元素
 * @param {HTMLElement} element 当前元素
 */
function getScrollParent(element) {
  // const style = (elem, prop) => {
  //   if (getComputedStyle !== undefined) {
  //     return getComputedStyle(elem, null).getPropertyValue(prop);
  //   }
  //   return elem.style[prop];
  // };
  // const overflow = node => style(node, 'overflow') + style(node, 'overflow-x') + style(node, 'overflow-y');
  // 循环判断父节点是否可滚动这里暂不添加,直接去直接父元素
  if (!(element instanceof HTMLElement)) {
    return window;
  }
  let parent = element;
  while (parent) {
    // 当前节点是body或者document
    if (parent === document.body || parent === document.documentElement) {
      break;
    }
    // 当期元素无父节点
    if (!parent.parentNode) {
      break;
    }
    // 判断节点是否含有overflow等属性的值
    if (parent.scrollHeight > parent.clientHeight) {
      return parent;
    }
    // if (/(scroll|auto|inherit)/.test(overflow(parent))) {
    //   return parent;
    // }
    parent = parent.parentNode;
  }
  return window;
}

let EmptyCompBox = ({ ...props }) => (
  <div {...props}>
    {/* <Spin size="large" className="lazyload-center-spin" /> */}
  </div>
);

class ScrollLoad extends React.Component {
  state = {
    visible: false,
  };

  componentDidMount() {
    let dom = findDOMNode(this); // 取得当前节点
    let parent = getScrollParent(dom);
    // console.log(dom,parent)

    this.parent = parent;
    let visible = this.checkVisible(dom, parent); // 初始化检查是否可见
    visible();
    this.scrollHandler = throttle(this.checkVisible(dom, parent), 100);
    parent.addEventListener('scroll', this.scrollHandler, { passive: true });
  }

  componentWillUnmount() {
    this.parent.removeEventListener('scroll', this.scrollHandler);
  }

  /**
   * 获取当前节点的offsetTop,如果不是直接父节点的话,通过循环获取
   */
  getNodeOffsetTop = (node, parent) => {
    if (!node || !parent) {
      this.setState({ visible: true });
      return 0;
    }
    let current = node;
    let offsetTop = 0;

     offsetTop += current.offsetTop
    // ==========ff================

    // while (current !== parent && current) {
    //   offsetTop += current.offsetTop;
    //   current = current.parentElement;
    // }

    // ==========ff================
    return offsetTop;
  };

  /**
   * 检测元素是否可见
   */
  checkVisible = (node, parent) => {
    if (!node || !parent) {
      this.setState({ visible: true });
      return null;
    }
    return () => {
      const { visible } = this.state;
      // 一旦可见下次取消事件监听
      if (visible) {
        this.parent.removeEventListener('scroll', this.scrollHandler);
        return; // 直接返回不执行当次eventListener
      }
      let seenHeight = parent.clientHeight || 0;
      let scrollHeight = parent.scrollTop || 0;
      let currentNode = findDOMNode(this); // 获取最新的dom结构
      let offsetTop = this.getNodeOffsetTop(currentNode, parent);
      // 1. 当偏移高度小于可见高度
      // 2. 初始不可见的时候,当可视高度+滚动高度大于了偏移高度
      // 3. 可以设置preLoad
      // console.log(offsetTop, seenHeight, scrollHeight)
      if (offsetTop <= seenHeight + scrollHeight) { //可视范围内
        this.setState({ visible: true });
      }
    };
  };

  render() {
    const { visible } = this.state;
    const { id, className, style } = this.props;
    return (
      <ReactPlaceHolder
        ready={visible}
        customPlaceholder={<EmptyCompBox id={id} className={className} style={style} />}
      >
        {this.props.children}
      </ReactPlaceHolder>
    );
  }
}

export default ScrollLoad;

  

原文地址:https://www.cnblogs.com/lisiyang/p/13667881.html