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