<div id='root'></div>
// 创建随机数
const createRandom = () => Math.floor(Math.random() * 1000);
// 创建一个图片url集合
const createSrc = (num = 10) =>  new Array(num).fill(0).map(() => {
    const index = createRandom();
    return `https://picsum.photos/200?random=${index}`;
  });
// 检查节点是否出现在视口
const checkVisible = (node, callback) => {
  const {top, height} = node.getBoundingClientRect();
  const innerHeight = window.innerHeight;
  top <= innerHeight && (top + height) > 0 &&  callback(true);
}

// 懒加载实现
const LazyLoad = (props) => {
  const ref = React.useRef(null);
  const [visible, setVisible] = React.useState(false);
  
  // 首次渲染,加载视口内的图片
  React.useEffect(() => {
    const node = ref.current
    if (node) {
      checkVisible(node, setVisible);
    }
  }, []);
  
  // 监听窗口滚动事件
  React.useEffect(() => {
    const node = ref.current
    
    const lazyLoadHandle = () => {
      checkVisible(node, setVisible);
    }
    
    if (node) {
      window.addEventListener('scroll', lazyLoadHandle)
    }
    
    return () => window.removeEventListener('scroll', lazyLoadHandle);
  }, []);
  
  return(
      <div ref={ref}>
        {visible ? props.children : (<div style={{height: props.height}} />)}
      </div>
  )
}

// 懒加载组件应用
const LazyLoadImage = ({ src }) => {
  return (
    <LazyLoad height='200px'>
      <img alt="" src={src} />
    </LazyLoad>
  );
};

function App() {
  return(
    <div>
      {createSrc(1000).map((item, index) => (
        <LazyLoadImage src={item} key={index} />
      ))}
    </div>
  )
}

ReactDOM.render(<App />, document.getElementById('root'))
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

  1. https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js
  2. https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js