背景:
页面做了rem自适应,会根据屏幕宽度自动调整html中的fontSize; 所以同接口返回同一组数据不同屏幕宽度会显示不同高度;
在设计稿尺寸下,如果接口返回数据有20条,虚拟盒子高度会被撑开而滚动,滚动时可以加载更多数据,这时候功能正常;
但是!!!在屏幕宽度比较小时,20条数据加载完还不能撑满盒子高度,导致虚拟列表没法滚动,加载更多,造成了事故!!!
这种问题应该还挺容易出现的,渲染不定高的虚拟列表,有时候确实会造成盒子不被撑满情况~
解决方式
(1)一次性获取多点数据,比如50条,保证盒子始终能被撑开(打补丁)
(2)组件中传入的高度ContainerHeight改成动态高度ContainerHeight * scale(这里的scale是动态的比例),根据屏幕大小变化
自己写一个下拉加载更多组件
使用# IntersectionObserver这个api
import { useRef, useEffect, useState } from 'react';
export default function IntersectionObserverDemo() {
const [items, setItems] = useState(Array.from({ length: 20 }));
const [hasMore, setHasMore] = useState(true);
const loaderRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
if (entries[0].isIntersecting && hasMore) {
// 模拟加载更多数据
setTimeout(() => {
setItems(prevItems => {
const newItems = [...prevItems, ...Array.from({ length: 20 })];
if (newItems.length >= 100) setHasMore(false);
return newItems;
});
}, 1000);
}
},
{ threshold: 1.0 } // 当 loader 元素完全进入视口时触发
);
if (loaderRef.current) {
observer.observe(loaderRef.current);
}
return () => {
if (loaderRef.current) {
observer.unobserve(loaderRef.current);
}
};
}, [hasMore]);
return (
<div>
<h1>使用 Intersection Observer</h1>
{items.map((_, index) => (
<div key={index} style={{ padding: '20px', border: '1px solid #ccc' }}>
项目 #{index + 1}
</div>
))}
{hasMore ? (
<div ref={loaderRef} style={{ textAlign: 'center', padding: '20px' }}>
加载更多...
</div>
) : (
<div style={{ textAlign: 'center', padding: '20px' }}>没有更多内容了</div>
)}
</div>
);
}
实现一个图片懒加载功能
import { useRef, useEffect } from 'react';
function LazyImage({ src, alt }) {
const imgRef = useRef();
useEffect(() => {
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.getAttribute('data-src');
observer.unobserve(img);
}
});
});
if (imgRef.current) {
observer.observe(imgRef.current);
}
return () => {
if (imgRef.current) {
observer.unobserve(imgRef.current);
}
};
}, []);
return <img ref={imgRef} data-src={src} alt={alt} />;
}
遗留其他待解决问题
对于服务端渲染的页面 如果做了rem自适应, 每次加载完客户端代码后,都会闪一下,因为html的fontSize可能会重新被赋值,感觉这种体验很不好,暂时没有找到比较好的解决方式。