懒加载

import React, { useRef, useEffect, useState } from 'react';
import Item from './item';
import styles from './index.module.less';

const Home = () => {
  const [itemsObj, setItemObj] = useState({});
  const [prevScrollTop, setPrevScrollTop] = useState(0);
  const [data, setData] = useState([1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
    11, 12, 13, 14, 15, 16, 17, 18, 19, 20]);
  const homeRef = useRef(null);

  const computedItems = () => {
    const homeRect = homeRef.current.getBoundingClientRect();

    const items = document.getElementsByName('item');

    items.forEach((item) => {
      const itemRect = item.getBoundingClientRect();

      itemsObj[item.id] = { ...(itemsObj[item.id] || {}), itemRect };

      // 距离底部20px就加载
      itemsObj[item.id].intoViewport = itemsObj[item.id].intoViewport
        || (itemRect.top - homeRect.top) < homeRect.height + 20;
    });

    setItemObj({ ...itemsObj });
  };

  useEffect(() => {
    computedItems();
  }, []);

  return (
    <div
      ref={homeRef}
      className={styles.home}
      onScroll={() => {
        window.clearTimeout(homeRef.current.watchTimer);
        homeRef.current.watchTimer = setTimeout(() => {
          const { current } = homeRef;
          const direction = current.scrollTop - prevScrollTop > 0 ? 'down' : 'up';

          // 向下滚动到离底部一段距离时,而且是第一次,就加载数据,
          // 这里通过prevScrollTop + current.clientHeight + 30 > current.scrollHeight来判断是否第一次
          const bottomDis = 50;
          const isReachedBottom = prevScrollTop + current.clientHeight
            + bottomDis > current.scrollHeight;

          if (direction === 'down'
            && !isReachedBottom
            && current.scrollTop + current.clientHeight + bottomDis > current.scrollHeight) {
            const len = data.length;
            for (let i = len + 1; i < len + 10; i += 1) {
              data.push(i);
            }
            setData([...data]);
          }
          setPrevScrollTop(current.scrollTop);
          computedItems();
        }, 50);
      }}
    >
      {
        data.map((i) => (
          <Item
            key={i}
            rect={itemsObj[i] || {}}
            i={i}
          />
        ))
      }
    </div>
  );
};
export default Home;
import React from 'react';
import styles from './index.module.less';

export default class Item extends React.Component {
  render() {
    const { i, rect } = this.props;
    return (
      <div
        className={styles.item}
        name="item"
        id={i}
      >
        <div>{i}</div>
        { rect.intoViewport ? '出现了' : '隐藏了'}
      </div>
    );
  }
}
.home{
  flex: 1;
  margin: 12px;
  overflow: auto;
}
.item{
  position: relative;
  background: white;
  margin-bottom: 12px;
  height: 100px;
  border-radius: 8px;
  border: 1px solid #D9D9D9;
  &:after{
    position: absolute;
    content: '';
    bottom: 0;
    height: 8px;
    left: 0;
    right: 0;
    background: red;
  }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值