如何先显示骨架屏再加载实际数据?React实现方法咨询
实现Airbnb式骨架屏+逐个加载效果的方案
核心原理
这种效果的核心是先渲染占位的骨架屏,然后通过监听资源加载状态或定时控制,将骨架屏逐个替换为真实内容,同时配合过渡动画提升视觉流畅度。
React 基础实现(无依赖库)
1. 单元素的骨架屏+加载切换
下面是一个基础的图片卡片组件,先显示骨架屏,图片加载完成后淡入显示真实内容:
import { useState } from 'react'; import './Card.css'; const ImageCard = ({ src, alt }) => { const [isLoaded, setIsLoaded] = useState(false); return ( <div className="card-container"> {/* 骨架屏 */} {!isLoaded && <div className="card-skeleton"></div>} {/* 真实内容 */} <img src={src} alt={alt} className={`card-image ${isLoaded ? 'loaded' : 'hidden'}`} onLoad={() => setIsLoaded(true)} onError={() => setIsLoaded(true)} // 加载失败也切换显示状态 /> </div> ); }; export default ImageCard;
对应的CSS(Card.css):
.card-container { position: relative; width: 200px; height: 200px; border-radius: 8px; overflow: hidden; } .card-skeleton { width: 100%; height: 100%; background: linear-gradient(90deg, #f0f0f0 25%, #e0e0e0 50%, #f0f0f0 75%); background-size: 200% 100%; animation: shimmer 1.5s infinite; } .card-image { position: absolute; top: 0; left: 0; width: 100%; height: 100%; object-fit: cover; transition: opacity 0.3s ease; } .card-image.hidden { opacity: 0; } .card-image.loaded { opacity: 1; } @keyframes shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
2. 批量元素逐个加载
如果是列表类场景,需要逐个触发加载效果,可以结合setTimeout和状态数组来控制每个元素的显示时机:
import { useState, useEffect } from 'react'; const ImageList = ({ images }) => { const [loadedIndices, setLoadedIndices] = useState([]); useEffect(() => { images.forEach((_, index) => { // 每个元素延迟150ms加载,模拟逐个出现的效果 setTimeout(() => { setLoadedIndices(prev => [...prev, index]); }, index * 150); }); }, [images]); return ( <div className="image-list"> {images.map((img, index) => ( <div key={index} className="list-item"> {!loadedIndices.includes(index) && <div className="card-skeleton"></div>} <img src={img.src} alt={img.alt} className={`card-image ${loadedIndices.includes(index) ? 'loaded' : 'hidden'}`} /> </div> ))} </div> ); }; export default ImageList;
简化实现的第三方库
如果不想手动写骨架屏样式和状态逻辑,可以用这些成熟的库:
- react-content-loader: 可以快速生成SVG骨架屏,支持自定义形状,内置加载动画,只需配置骨架结构即可。
- shimmer-react: 专门用于实现闪光(shimmer)效果的骨架屏,API简洁,适合快速集成。
- react-skeleton-loader: 轻量的骨架屏组件,支持自定义样式和动画。
以react-content-loader为例,快速实现列表骨架屏:
import ContentLoader from 'react-content-loader'; const ListSkeleton = () => ( <ContentLoader speed={2} width={400} height={160} viewBox="0 0 400 160" backgroundColor="#f3f3f3" foregroundColor="#ecebeb" > <rect x="0" y="0" rx="8" ry="8" width="70" height="70" /> <rect x="80" y="17" rx="4" ry="4" width="300" height="13" /> <rect x="80" y="40" rx="4" ry="4" width="250" height="13" /> <rect x="80" y="63" rx="4" ry="4" width="170" height="13" /> </ContentLoader> ); // 在组件中使用: const List = ({ items, isLoading }) => { if (isLoading) return <ListSkeleton />; return ( <div className="list"> {items.map(item => <ListItem key={item.id} {...item} />)} </div> ); };
注意事项
- 优先监听真实资源的
onLoad事件,而不是固定setTimeout,这样更符合真实加载场景,避免内容未加载完成就出现占位消失的情况。 - 骨架屏的样式尽量贴近真实内容的布局和尺寸,减少视觉跳动。
- 可以结合React的Suspense和Lazy Loading实现更高级的代码分割+骨架屏效果。
内容的提问来源于stack exchange,提问作者Jonathan Lightbringer
相关产品推荐
相关产品推荐

