如何实现react-loading-skeleton响应式:桌面3行/移动端5行?
实现响应式React骨架屏(避免布局偏移)
要实现桌面端3行、移动端5行的响应式骨架屏,同时避免内容加载时的布局跳转,核心是让骨架屏的总高度与对应屏幕下实际内容的高度完全匹配,以下是两种实用方案:
方案一:使用自定义useMediaQuery钩子(React推荐方案)
通过监听屏幕尺寸变化,动态调整骨架屏的行数,同时严格对齐实际内容的行高与间距:
1. 实现自定义媒体查询钩子
import { useState, useEffect } from 'react'; const useMediaQuery = (query) => { const [matches, setMatches] = useState(false); useEffect(() => { const media = window.matchMedia(query); setMatches(media.matches); const updateMatch = () => setMatches(media.matches); window.addEventListener('resize', updateMatch); return () => window.removeEventListener('resize', updateMatch); }, [query]); return matches; };
2. 在组件中应用
import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import 'react-loading-skeleton/dist/skeleton.css'; const MyComponent = () => { const [loading, setLoading] = useState(true); // 定义移动端断点(可根据需求调整) const isMobile = useMediaQuery('(max-width: 767px)'); // 动态设置骨架屏行数 const skeletonCount = isMobile ? 5 : 3; // 模拟数据加载 useEffect(() => { setTimeout(() => setLoading(false), 2000); }, []); return ( <div style={{ width: '100%' }}> {loading ? ( <SkeletonTheme baseColor="#222222" highlightColor="#000"> <Skeleton height="24px" count={skeletonCount} width="100%" borderRadius="4px" style={{ marginBottom: '8px' }} // 与实际内容的行间距保持一致 /> </SkeletonTheme> ) : ( <MyText style={{ lineHeight: '24px', marginBottom: '8px' }}> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor? </MyText> )} </div> ); }; // 确保自定义文本组件的行高与骨架屏匹配 const MyText = ({ children, style }) => ( <p style={{ margin: 0, ...style }}>{children}</p> );
方案二:纯CSS控制(无JS状态依赖)
提前渲染所有可能的骨架行,通过CSS媒体查询控制不同屏幕下的显示行数:
1. 组件代码
import { useState, useEffect } from 'react'; import Skeleton, { SkeletonTheme } from 'react-loading-skeleton'; import 'react-loading-skeleton/dist/skeleton.css'; const MyComponent = () => { const [loading, setLoading] = useState(true); useEffect(() => { setTimeout(() => setLoading(false), 2000); }, []); return ( <div style={{ width: '100%' }}> {loading ? ( <SkeletonTheme baseColor="#222222" highlightColor="#000"> <div className="skeleton-container"> {/* 固定渲染5行,通过CSS控制桌面端隐藏后2行 */} <Skeleton height="24px" width="100%" borderRadius="4px" style={{ marginBottom: '8px' }} /> <Skeleton height="24px" width="100%" borderRadius="4px" style={{ marginBottom: '8px' }} /> <Skeleton height="24px" width="100%" borderRadius="4px" style={{ marginBottom: '8px' }} /> <Skeleton height="24px" width="100%" borderRadius="4px" style={{ marginBottom: '8px' }} className="mobile-only" /> <Skeleton height="24px" width="100%" borderRadius="4px" className="mobile-only" /> </div> </SkeletonTheme> ) : ( <MyText style={{ lineHeight: '24px', marginBottom: '8px' }}> Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor. Lorem ipsum dolor sit amet consectetur, adipisicing elit. Suscipit, dolor? </MyText> )} </div> ); }; const MyText = ({ children, style }) => ( <p style={{ margin: 0, ...style }}>{children}</p> );
2. 配套CSS
/* 桌面端(≥768px)隐藏移动端专属骨架行 */ @media (min-width: 768px) { .mobile-only { display: none; } } /* 移动端确保所有骨架行显示 */ @media (max-width: 767px) { .mobile-only { display: block; } }
关键注意事项
- 高度对齐:骨架屏的
height必须与实际内容的lineHeight完全一致,行间距(margin/padding)也要一一对应,这是避免布局跳转的核心。 - 断点一致性:响应式断点要和项目整体的断点规则保持统一,避免出现适配混乱。
内容的提问来源于stack exchange,提问作者Alex Smagin
相关产品推荐
相关产品推荐

