Skeleton 骨架屏
页面加载占位,呈现内容大致结构。区别于 Shimmer(聊天专属流式占位)——Skeleton 是页面级。
实时预览
下方渲染的就是 src/components/ui/Skeleton/* 本体(reanimated 4 worklet 驱动 opacity 脉冲),通过 react-native-web 翻译成浏览器节点。
列表项骨架卡片骨架
视觉规范
来源:src/components/ui/Skeleton/Skeleton.tsx、types.ts、共享 usePulse。
| 元素 | 规则 |
|---|---|
| 颜色 | c.surfaceContainerHigh(亮色 #F0F0F0) |
| 圆角 | line:3px / rect:8px / circle:size/2(均可用 radius 覆盖) |
| 动画 | opacity 脉冲(共享 usePulse hook,传 from: 0.5),半周期 700ms、全周期 1.4s,0.5 ↔ 1 循环 |
形状
shape | 默认值 | 用途 |
|---|---|---|
'line' | width 100% / height 11 / radius 3 | 文本占位 |
'rect'(默认) | width 100% / height 80 / radius 8 | 图片 / 卡片占位 |
'circle' | size 40 / radius = size/2 | 头像占位 |
API
来源:src/components/ui/Skeleton/types.ts、Skeleton.tsx。
| Prop | 类型 | 默认 | 说明 |
|---|---|---|---|
shape | 'line' | 'rect' | 'circle' | 'rect' | 形状,决定默认尺寸与圆角 |
width | DimensionValue? | 形状相关 | 宽度(line / rect);circle 忽略,走 size |
height | number? | 形状相关 | 高度(line / rect);circle 忽略,走 size |
size | number? | 40 | 直径(circle);line / rect 忽略 |
radius | number? | 形状相关 | 覆盖圆角(line 3 / rect 8 / circle size/2) |
style | StyleProp<ViewStyle>? | — | 额外样式覆盖 |
testID | string? | — | E2E / 测试定位 |
用法
import { Skeleton } from '@unif/react-native-design';
{/* 列表项骨架 */}
<View>
<Skeleton shape="circle" size={40} />
<View style={{ flex: 1, gap: 8 }}>
<Skeleton shape="line" width="60%" height={14} />
<Skeleton shape="line" width="80%" height={11} />
</View>
</View>
{/* 卡片骨架 */}
<Skeleton shape="rect" width="100%" height={120} radius={12} />
单一组件 +
shapeprop(MUI Skeleton 同款 variant 模式),旧的Skeleton.Line / .Rect / .Circle命名空间访问已移除。
无障碍(a11y)
来源:src/components/ui/Skeleton/Skeleton.tsx、types.ts。
加载占位骨架为纯视觉元素,无交互。源码在其 <Animated.View> 上显式设 accessibilityElementsHidden + importantForAccessibility="no-hide-descendants",对 SR 完全隐藏——占位块没有朗读价值,隐藏可避免在加载阶段读出无意义节点。无 accessibilityRole / accessibilityLabel,也无可传的 a11y prop(仅 shape / width / height / size / radius / style / testID)。加载完成后用真实内容整体替换骨架即可,真实内容自带其语义。
与 Shimmer 的区别
| Skeleton | Shimmer (chat) |
|---|---|
| 页面级,初次加载 | 单个气泡里,AI 思考中 |
| 整体块状(卡片、行) | 几行不等宽 + 头像 |
| 加载完成后整体替换 | 气泡内文字流式填充 |