骨架屏
在加载数据时,如果需要为终端用户提供丰富的视觉和交互体验,可以选择 skeleton 骨架屏。
基础用法
基础骨架屏。
<template>
<el-skeleton />
<br />
<el-skeleton style="--el-skeleton-circle-size: 100px">
<template #template>
<el-skeleton-item variant="circle" />
</template>
</el-skeleton>
</template>
可配置的行数
您可以自行配置行数,为了获得更精确的渲染效果,实际渲染的行数将始终比给定数字多 1 行,这是因为我们正在渲染一个宽度为其他行 33% 的标题行。
动画效果
我们提供了一个名为 animated 的开关标志,用于指示是否显示加载动画。当此项为 true 时,el-skeleton 的所有子级都将显示动画效果。
自定义模板
Element Plus 仅提供最常用的模板,有时这可能会成为一个问题,因此您可以使用名为 template 的插槽来完成该工作。
此外,我们还提供了不同类型的骨架单元供您选择,更多详细信息请滚动到页面底部查看 API 说明。另外,在构建您自己的自定义骨架结构时,应使其结构尽可能接近真实的 DOM,从而避免由高度差引起的 DOM 抖动。
<template>
<el-skeleton style="width: 240px">
<template #template>
<el-skeleton-item variant="image" style="width: 240px; height: 240px" />
<div style="padding: 14px">
<el-skeleton-item variant="p" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
</el-skeleton>
</template>
加载状态
当加载结束时,我们总是需要向终端用户展示带有真实数据的 UI。通过 loading 属性,我们可以控制是否显示真实的 DOM。您也可以使用 default 插槽来构建真实的 DOM 元素。
<template>
<el-space direction="vertical" alignment="flex-start">
<div>
<label style="margin-right: 16px">Switch Loading</label>
<el-switch v-model="loading" />
</div>
<el-skeleton style="width: 240px" :loading="loading" animated>
<template #template>
<el-skeleton-item variant="image" style="width: 240px; height: 240px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
<template #default>
<el-card :body-style="{ padding: '0px', marginBottom: '1px' }">
<img
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
class="image"
/>
<div style="padding: 14px">
<span>Delicious hamburger</span>
<div class="bottom card-header">
<div class="time">{{ currentDate }}</div>
<el-button text class="button">Operation button</el-button>
</div>
</div>
</el-card>
</template>
</el-skeleton>
</el-space>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(true)
const currentDate = new Date().toDateString()
</script>
渲染数据列表
大多数情况下,骨架屏被用作尚未从服务器获取的数据列表渲染的指示器。这时,我们需要凭空创建一组骨架屏列表,使其看起来像是在加载中。通过 count 属性,您可以控制需要渲染到浏览器的此类模板的数量。
提示
我们不建议在浏览器中渲染大量虚假 UI,这仍然会导致性能问题,且销毁骨架屏所需的时间也会更长。尽量保持 count 较小,以提供更好的用户体验。
<template>
<el-space style="width: 100%" fill>
<div>
<el-button @click="setLoading">Click me to reload</el-button>
</div>
<el-skeleton
style="display: flex; gap: 8px"
:loading="loading"
animated
:count="3"
>
<template #template>
<div style="flex: 1">
<el-skeleton-item variant="image" style="height: 240px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</div>
</template>
<template #default>
<el-card
v-for="item in lists"
:key="item.name"
:body-style="{ padding: '0px', marginBottom: '1px' }"
>
<img
:src="item.imgUrl"
class="image multi-content"
style="max-width: 100%"
/>
<div style="padding: 14px">
<span>{{ item.name }}</span>
<div class="bottom card-header">
<div class="time">{{ currentDate }}</div>
<el-button text class="button">Operation button</el-button>
</div>
</div>
</el-card>
</template>
</el-skeleton>
</el-space>
</template>
<script lang="ts" setup>
import { onMounted, ref } from 'vue'
interface ListItem {
imgUrl: string
name: string
}
const loading = ref(true)
const lists = ref<ListItem[]>([])
const currentDate = new Date().toDateString()
const setLoading = () => {
loading.value = true
setTimeout(() => {
loading.value = false
}, 2000)
}
onMounted(() => {
loading.value = false
lists.value = [
{
imgUrl:
'https://fuss10.elemecdn.com/a/3f/3302e58f9a181d2509f3dc0fa68b0jpeg.jpeg',
name: 'Deer',
},
{
imgUrl:
'https://fuss10.elemecdn.com/1/34/19aa98b1fcb2781c4fba33d850549jpeg.jpeg',
name: 'Horse',
},
{
imgUrl:
'https://fuss10.elemecdn.com/0/6f/e35ff375812e6b0020b6b4e8f9583jpeg.jpeg',
name: 'Mountain Lion',
},
]
})
</script>
防止渲染抖动
有时 API 响应非常快,这种情况下,骨架屏刚渲染到 DOM 就需要切换回真实的 DOM,这会导致瞬间的闪烁。为了避免这种情况,您可以使用 throttle 属性。
提示
自 2.8.8 版本起,throttle 属性支持两种值:number 和 object。传递 number 时,相当于 {leading: xxx},控制骨架屏显示的节流。当然,您也可以通过传递 {trailing: xxx} 来控制骨架屏消失的节流。

<template>
<el-space direction="vertical" alignment="flex-start">
<div>
<label style="margin-right: 16px">Switch Loading</label>
<el-switch v-model="loading" />
</div>
<el-skeleton
style="width: 240px"
:loading="loading"
animated
:throttle="500"
>
<template #template>
<el-skeleton-item variant="image" style="width: 240px; height: 265px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
<template #default>
<el-card :body-style="{ padding: '0px', marginBottom: '1px' }">
<img
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
class="image"
/>
<div style="padding: 14px">
<span>Delicious hamburger</span>
<div class="bottom card-header">
<div class="time">{{ currentDate }}</div>
<el-button text class="button">operation button</el-button>
</div>
</div>
</el-card>
</template>
</el-skeleton>
</el-space>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const currentDate = new Date().toDateString()
</script>
初始渲染加载 2.8.8
当 loading 的初始值为 true 时,您可以设置 throttle: {initVal: true, leading: xxx} 来控制初始骨架屏立即显示而无需节流。
<template>
<el-space direction="vertical" alignment="flex-start">
<div>
<label style="margin-right: 16px">Switch Loading</label>
<el-switch v-model="loading" />
</div>
<el-skeleton
style="width: 240px"
:loading="loading"
animated
:throttle="{ leading: 500, initVal: true }"
>
<template #template>
<el-skeleton-item variant="image" style="width: 240px; height: 265px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
<template #default>
<el-card :body-style="{ padding: '0px', marginBottom: '1px' }">
<img
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
class="image"
/>
<div style="padding: 14px">
<span>Delicious hamburger</span>
<div class="bottom card-header">
<div class="time">{{ currentDate }}</div>
<el-button text class="button">operation button</el-button>
</div>
</div>
</el-card>
</template>
</el-skeleton>
</el-space>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(true)
const currentDate = new Date().toDateString()
</script>
无抖动切换显示/隐藏 2.8.8
提示
您可以设置 throttle: {initVal: true, leading: xxx, trailing: xxx} 来控制骨架屏效果的初始显示,并使切换加载状态时骨架屏的过渡更加平滑。
有时您希望在切换显示或隐藏加载时,能更平滑地渲染业务组件。您可以设置 throttle: {leading: xxx, trailing:xxx} 来控制渲染抖动。
<template>
<el-space direction="vertical" alignment="flex-start">
<div>
<label style="margin-right: 16px">Switch Loading</label>
<el-switch v-model="loading" />
</div>
<el-skeleton
style="width: 240px"
:loading="loading"
animated
:throttle="{ leading: 500, trailing: 500, initVal: true }"
>
<template #template>
<el-skeleton-item variant="image" style="width: 240px; height: 265px" />
<div style="padding: 14px">
<el-skeleton-item variant="h3" style="width: 50%" />
<div
style="
display: flex;
align-items: center;
justify-items: space-between;
margin-top: 16px;
height: 16px;
"
>
<el-skeleton-item variant="text" style="margin-right: 16px" />
<el-skeleton-item variant="text" style="width: 30%" />
</div>
</div>
</template>
<template #default>
<el-card :body-style="{ padding: '0px', marginBottom: '1px' }">
<img
src="https://shadow.elemecdn.com/app/element/hamburger.9cf7b091-55e9-11e9-a976-7f4d0b07eef6.png"
class="image"
/>
<div style="padding: 14px">
<span>Delicious hamburger</span>
<div class="bottom card-header">
<div class="time">{{ currentDate }}</div>
<el-button text class="button">operation button</el-button>
</div>
</div>
</el-card>
</template>
</el-skeleton>
</el-space>
</template>
<script lang="ts" setup>
import { ref } from 'vue'
const loading = ref(false)
const currentDate = new Date().toDateString()
</script>
骨架屏 API
骨架屏属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| animated | 是否显示动画效果 | boolean | false |
| count | 渲染到 DOM 的虚假条目数量 | number | 1 |
| 加载中 | 是否显示真实的 DOM | boolean | false |
| 行数 | 行数,仅在未提供 template 插槽时有效 | number | 3 |
| throttle | 渲染延迟(以毫秒为单位)。数字表示延迟显示,也可以设置为延迟隐藏,例如 { leading: 500, trailing: 500 }。当需要控制 loading 的初始值时,可以设置 { initVal: true } | number / object | 0 |
骨架屏插槽
| 名称 | 描述 | 类型 |
|---|---|---|
| default | 真实渲染的 DOM | object |
| template | 作为渲染骨架屏模板的内容 | object |
骨架屏单元 API
骨架屏单元属性
| 名称 | 描述 | 类型 | 默认值 |
|---|---|---|---|
| variant | 当前渲染的骨架屏类型 | 枚举 | 文本 |