前端实现模块懒加载

通常对于无规则长列表带来的加载耗时长、性能差的问题,首先想到的方案就是通过滚动位置判断当前模块是否进入视图中,来判断模块是否加载。这样有两个弊端:
1. 要预先知道每个模块的准确高度。通常情况下这个高度的是动态的,难以在初始状态下获取所有模块的高度
2. 要实时计算滚动位置,来判断模块是否进去视图

利用交叉观察器IntersectionObserver API的特性,可以自动"观察"元素是否可见,Chrome 51+ 已经支持。在react中的具体实现demo如下:

在父组件中声明

const intersectionEntriesMapRef = useRef<WeakMap<Element, (isIntersecting:boolean) => void>>(new WeakMap([]));
// IntersectionObserver实例
const intersectionObserverRef = useRef<IntersectionObserver>(
    new IntersectionObserver(entries => {
      entries.forEach(({ target, isIntersecting }) => {
        intersectionEntriesMapRef.current.get(target)?.(isIntersecting);
    });
  })
);

实例化子组件的时候传入intersectionObserverRef、intersectionEntriesMapRef

<ChildCom
  intersectionObserverRef={intersectionObserverRef}
  intersectionEntriesMapRef={intersectionEntriesMapRef}
  contentDefaultHeight={283}
  ...
/>

通过contentDefaultHeight对子模块的高度进行预估

子模块ChildCom中监听加载,获取准确高度,并通过observe挂载在intersectionObserverRef上

const [contentShow, setContentShow] = useState(false);
// 子模块内容区域dom绑定
const contentWrapRef = useRef<HTMLDivElement>(null);
// 子模块内容区域高度缓存
const contentHeightRef = useRef<number>(contentDefaultHeight ?? 0);

useEffect(() => {
  const _contentWrapRef = contentWrapRef.current;
  const _intersectionObserverRef = intersectionObserverRef?.current;
  intersectionEntriesMapRef?.current?.set(_contentWrapRef, isIntersecting => {
    setContentShow(isIntersecting);
    isIntersecting &&
      requestAnimationFrame(() => {
        contentHeightRef.current = _contentWrapRef?.offsetHeight;
      });
  });
  _intersectionObserverRef?.observe(_contentWrapRef);
  return () => {
    _intersectionObserverRef?.unobserve(_contentWrapRef);
  };
}, []);

return (
	<div ref={contentWrapRef}>
		{
			contentShow ? <div>你的模块内容</div> : <></>
		}
	</div>
);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值