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>自定义尺寸
通过 width 和 height 属性可以自定义骨架屏的尺寸。
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 | 是否显示加载状态 | boolean | true |
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 | 是否激活动画 | boolean | true |
width | 宽度 | string | number | undefined |
height | 高度 | string | number | undefined |
count | 重复次数 | number | 1 |
avatar | 是否显示头像 | boolean | false |
avatar-shape | 头像形状 | 'circle' | 'square' | 'rounded' | 'circle' |
avatar-size | 头像尺寸 | string | number | undefined |
title | 是否显示标题 | boolean | false |
title-width | 标题宽度 | string | number | undefined |
rows | 段落行数 | number | 3 |
rows-width | 段落宽度 | (string | number)[] | string | undefined |
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;
}