Skip to content

Skeleton 骨架屏

在需要等待加载内容的位置提供一个占位图形组合,提升用户体验。

基础用法

最简单的占位效果。

内容加载中,请稍候...
vue
<template>
  <ExSkeleton />
</template>

复杂组合

更复杂的组合,包含头像、标题和段落。

内容加载中,请稍候...
vue
<template>
  <ExSkeleton avatar :title="true" :rows="4" />
</template>

动画效果

通过 animation 属性可以设置不同的动画效果。

脉冲动画(默认)

内容加载中,请稍候...

波浪动画

内容加载中,请稍候...

无动画

内容加载中,请稍候...
vue
<template>
  <!-- 脉冲动画 -->
  <ExSkeleton animation="pulse" avatar :title="true" :rows="3" />
  
  <!-- 波浪动画 -->
  <ExSkeleton animation="wave" avatar :title="true" :rows="3" />
  
  <!-- 无动画 -->
  <ExSkeleton animation="none" avatar :title="true" :rows="3" />
</template>

不同变体

通过 variant 属性可以使用预设的骨架屏样式。

文本

内容加载中,请稍候...

头像

内容加载中,请稍候...

标题

内容加载中,请稍候...

段落

内容加载中,请稍候...

图片

内容加载中,请稍候...

按钮

内容加载中,请稍候...

卡片

内容加载中,请稍候...

文章

内容加载中,请稍候...
vue
<template>
  <!-- 文本 -->
  <ExSkeleton variant="text" />
  
  <!-- 头像 -->
  <ExSkeleton variant="avatar" />
  
  <!-- 标题 -->
  <ExSkeleton variant="title" />
  
  <!-- 段落 -->
  <ExSkeleton variant="paragraph" :rows="4" />
  
  <!-- 图片 -->
  <ExSkeleton variant="image" />
  
  <!-- 按钮 -->
  <ExSkeleton variant="button" />
  
  <!-- 卡片 -->
  <ExSkeleton variant="card" />
  
  <!-- 文章 -->
  <ExSkeleton variant="article" :rows="5" />
</template>

显示真实内容

通过 loading 属性控制是否显示骨架屏。

内容加载中,请稍候...
vue
<script setup>
import { ref } from 'vue'

const loading = ref(true)

const toggleLoading = () => {
  loading.value = !loading.value
}
</script>

<template>
  <ExButton type="primary" @click="toggleLoading">
    {{ loading ? '显示内容' : '显示骨架屏' }}
  </ExButton>
  
  <ExSkeleton :loading="loading" avatar :title="true" :rows="3">
    <template #content>
      <ExPanel type="primary">
        <template #icon>
          <img src="https://api.iconify.design/ri/user-line.svg" alt="用户" width="24" height="24" />
        </template>
        <div>
          <h3>玩家信息</h3>
          <p>这是加载完成后显示的真实内容</p>
        </div>
      </ExPanel>
    </template>
  </ExSkeleton>
</template>

列表骨架屏

使用 count 属性可以渲染多个骨架屏,适合列表场景。

内容加载中,请稍候...
vue
<script setup>
import { ref } from 'vue'

const loading = ref(true)
</script>

<template>
  <ExSkeleton :loading="loading" avatar :title="true" :rows="2" :count="3">
    <template #content>
      <div v-for="i in 3" :key="i">
        <ExPanel type="primary" hoverable>
          <div>
            <h4>玩家 {{ i }}</h4>
            <p>等级 {{ 40 + i * 5 }}</p>
          </div>
        </ExPanel>
      </div>
    </template>
  </ExSkeleton>
</template>

自定义尺寸

通过 widthheight 属性可以自定义骨架屏的尺寸。

内容加载中,请稍候...
内容加载中,请稍候...
内容加载中,请稍候...
内容加载中,请稍候...
vue
<template>
  <ExSkeleton variant="text" width="200px" />
  <ExSkeleton variant="text" width="50%" />
  <ExSkeleton variant="image" width="100%" height="150px" />
  <ExSkeleton variant="button" width="120px" height="40px" />
</template>

自定义段落宽度

通过 rowsWidth 属性可以自定义每行的宽度。

内容加载中,请稍候...
vue
<template>
  <ExSkeleton 
    :title="true" 
    :rows="4" 
    :rows-width="['100%', '90%', '80%', '60%']"
  />
</template>

头像形状

通过 avatarShape 属性可以设置头像的形状。

圆形头像

内容加载中,请稍候...

方形头像

内容加载中,请稍候...

圆角头像

内容加载中,请稍候...
vue
<template>
  <!-- 圆形头像 -->
  <ExSkeleton avatar avatar-shape="circle" :title="true" :rows="2" />
  
  <!-- 方形头像 -->
  <ExSkeleton avatar avatar-shape="square" :title="true" :rows="2" />
  
  <!-- 圆角头像 -->
  <ExSkeleton avatar avatar-shape="rounded" :title="true" :rows="2" />
</template>

不同尺寸

通过 size 属性可以设置骨架屏的尺寸。

小尺寸

内容加载中,请稍候...

默认尺寸

内容加载中,请稍候...

大尺寸

内容加载中,请稍候...
vue
<template>
  <!-- 小尺寸 -->
  <ExSkeleton size="small" avatar :title="true" :rows="3" />
  
  <!-- 默认尺寸 -->
  <ExSkeleton size="default" avatar :title="true" :rows="3" />
  
  <!-- 大尺寸 -->
  <ExSkeleton size="large" avatar :title="true" :rows="3" />
</template>

自定义骨架屏

使用默认插槽可以完全自定义骨架屏的内容。

内容加载中,请稍候...
内容加载中,请稍候...
内容加载中,请稍候...
内容加载中,请稍候...
vue
<script setup>
import { ref } from 'vue'

const loading = ref(true)
</script>

<template>
  <ExSkeleton :loading="loading" variant="custom">
    <!-- 自定义骨架屏 -->
    <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;">
      <ExSkeleton variant="card" v-for="i in 3" :key="i" />
    </div>
    
    <!-- 真实内容 -->
    <template #content>
      <div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px;">
        <ExPanel v-for="i in 3" :key="i" type="primary" hoverable>
          <div>卡片内容 {{ i }}</div>
        </ExPanel>
      </div>
    </template>
  </ExSkeleton>
</template>

API

Skeleton Props

属性说明类型默认值
loading是否显示加载状态booleantrue
animation动画类型'pulse' | 'wave' | 'none''pulse'
shape形状'circle' | 'square' | 'rounded''rounded'
size尺寸'small' | 'default' | 'large''default'
variant变体类型'text' | 'avatar' | 'title' | 'paragraph' | 'image' | 'button' | 'card' | 'list' | 'table' | 'article' | 'custom''text'
active是否激活动画booleantrue
width宽度string | numberundefined
height高度string | numberundefined
count重复次数number1
avatar是否显示头像booleanfalse
avatar-shape头像形状'circle' | 'square' | 'rounded''circle'
avatar-size头像尺寸string | numberundefined
title是否显示标题booleanfalse
title-width标题宽度string | numberundefined
rows段落行数number3
rows-width段落宽度(string | number)[] | stringundefined

Skeleton Slots

插槽名说明
default自定义骨架屏内容(variant="custom" 时)
content加载完成后显示的真实内容

Skeleton Methods

方法名说明类型
getElement获取骨架屏DOM元素() => HTMLDivElement | null

无障碍支持

  • 使用 role="status" 标识加载状态
  • 使用 aria-label 提供加载提示
  • 使用 aria-live="polite" 通知屏幕阅读器
  • 使用 aria-busy="true" 标识忙碌状态
  • 支持 prefers-reduced-motion 减少动画

主题定制

可以通过 CSS 变量自定义骨架屏样式:

css
:root {
  --ex-skeleton-bg: linear-gradient(135deg, rgba(0, 240, 255, 0.1), rgba(255, 0, 127, 0.1));
  --ex-skeleton-border: rgba(0, 240, 255, 0.2);
  --ex-skeleton-animation-duration: 2s;
}