Skeleton 骨架屏

内容加载期间保持其形状的占位块。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Avatar, Button, Card, Inline, Skeleton, Stack, Text } from '@hina-ui/vue'

  const loading = ref(true)
</script>

<template>
  <Stack class="w-full max-w-sm">
    <Card>
      <Inline gap="sm" align="start">
        <Skeleton :loading="loading" class="rounded-full">
          <Avatar size="lg" src="/avatars/selfie.webp" alt="星见书音" />
        </Skeleton>
        <Stack gap="xs" class="min-w-0 flex-1">
          <Skeleton :loading="loading">
            <Text class="font-medium">星见书音</Text>
          </Skeleton>
          <Skeleton :loading="loading">
            <Text tone="muted" size="sm">翻译了 128 本轻小说</Text>
          </Skeleton>
        </Stack>
      </Inline>
    </Card>
    <Button size="sm" variant="soft" tone="neutral" @click="loading = !loading">
      {{ loading ? '显示内容' : '显示骨架' }}
    </Button>
  </Stack>
</template>
vue

用法

import { Skeleton } from '@hina-ui/vue'
ts

用它包住真实内容,再传入 loading。loading 为真时内容隐藏但仍然参与布局,因此占位块的尺寸与内容将来的尺寸完全一致;loading 变为假之后包裹元素消失,只剩内容本身。

<script setup lang="ts">
  import { ref } from 'vue'
  import { Button, Inline, Skeleton, Stack, Text } from '@hina-ui/vue'

  const loading = ref(true)
</script>

<template>
  <Stack class="w-full max-w-sm">
    <Inline>
      <Skeleton :loading="loading">
        <Text>ATRI</Text>
      </Skeleton>
      <Skeleton :loading="loading">
        <Text tone="muted" size="sm">第 42 章</Text>
      </Skeleton>
    </Inline>
    <Button size="sm" variant="soft" tone="neutral" @click="loading = !loading">
      {{ loading ? '加载完成' : '重新加载' }}
    </Button>
  </Stack>
</template>
vue

不放内容时,Skeleton 就是一个普通的块,尺寸由类名给出。

<script setup lang="ts">
  import { Skeleton, Stack } from '@hina-ui/vue'
</script>

<template>
  <Stack gap="sm" class="w-full max-w-sm">
    <Skeleton class="h-4 w-1/3" />
    <Skeleton class="h-4 w-full" />
    <Skeleton class="h-4 w-4/5" />
  </Stack>
</template>
vue

示例

形状

形状完全由类名决定:图片用圆角矩形,头像用 rounded-full,一行文字用一条短块。

<script setup lang="ts">
  import { Card, Inline, Skeleton, Stack } from '@hina-ui/vue'
</script>

<template>
  <Card class="w-full max-w-sm">
    <Stack gap="sm">
      <Skeleton class="h-32 w-full rounded-lg" />
      <Inline gap="sm" align="center">
        <Skeleton class="size-10 rounded-full" />
        <Stack gap="xs" class="flex-1">
          <Skeleton class="h-4 w-1/2" />
          <Skeleton class="h-3 w-1/3" />
        </Stack>
      </Inline>
    </Stack>
  </Card>
</template>
vue

行为

  • 渐变光带从左向右扫过固定底色,默认周期为 1.2 秒;RTL 布局中方向反转。
  • 系统开启减弱动态效果时停止扫光,占位块保持静止。
  • loading 为假时组件只渲染插槽内容,不留下任何包裹元素。

无障碍

  • 占位块带 aria-hidden 和 inert,屏幕阅读器会跳过它,其中的内容也无法获得焦点。
  • 加载状态在拥有它的区域上播报,不必在每个占位块上重复。

API

属性
类型
默认值
说明
loading
boolean
true
是否显示占位块
as
string
'span'
渲染的标签
class
string
—
追加至占位块的类名
插槽
说明
default
真实内容,占位块的尺寸取自它