通常对于无规则长列表带来的加载耗时长、性能差的问题,首先想到的方案就是通过滚动位置判断当前模块是否进入视图中,来判断模块是否加载。这样有两个弊端:
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>
);
522

被折叠的 条评论
为什么被折叠?



