Skeleton 骨架屏
17:06说明
数据加载期间的占位骨架。loading=true 时按 avatar / title / rows 渲染对应的灰色占位块,loading=false 时改为渲染默认插槽的真实内容,实现原位替换;animate 控制各占位块内的扫光动画。
兼容性
| 平台 | 支持情况 |
|---|---|
| App | ✅ 支持(扫光由 UniElement.animate 逐条驱动,渐变降级为单向两色) |
| H5 | ✅ 支持(扫光由 CSS @keyframes 驱动) |
| 微信小程序 | ✅ 支持(扫光由 CSS @keyframes 驱动) |
示例
基础用法
默认展示标题 + 段落占位图,loading=true 时显示骨架。
查看源码
vue
<template>
<ux-skeleton :loading="true" :rows="3" />
</template>段落行数 rows
通过 rows 设置段落占位图的行数。
查看源码
vue
<template>
<ux-skeleton :loading="true" :rows="rows" />
<view class="btn-wrap">
<ux-button v-for="(item, index) in rowsList" :key="index" :type="rows === item.value ? 'primary' : 'default'" custom-class="btn-item" @click="rows = item.value">{{ item.label }}</ux-button>
</view>
</template>
<script setup lang="uts">
const rows = ref<number>(3);
const rowsList = [
{ value: 2, label: '2' },
{ value: 3, label: '3' },
{ value: 5, label: '5' }
];
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
align-items: center;
margin-top: 10px;
}
.btn-item {
margin-right: 12px;
}
</style>自定义宽度/高度
rows-width / rows-height 支持数组按行设置,title-width / title-height 设置标题尺寸。
查看源码
vue
<template>
<ux-skeleton :loading="true" :rows="3" :rows-width="['100%', '80%', '60%']" :rows-height="['25', '25', '25']" :title-width="'40%'" :title-height='30' />
</template>头像 avatar
avatar=true 显示头像占位图,avatar-shape 支持 circle / square。
查看源码
vue
<template>
<ux-skeleton :loading="true" :rows="3" avatar :avatar-size="20" avatar-shape="circle" />
</template>动画开关 animate
animate 控制扫光动画,可点击按钮切换开/关对比效果。
查看源码
vue
<template>
<ux-skeleton :loading="true" :rows="3" :animate="animate" />
<view class="btn-wrap">
<ux-button :type="animate ? 'primary' : 'default'" @click="animate = !animate">{{ animate ? '开启动画' : '关闭动画' }}</ux-button>
</view>
</template>
<script setup lang="uts">
const animate = ref<boolean>(true);
</script>
<style scoped>
.btn-wrap {
display: flex;
flex-direction: row;
flex-wrap: wrap;
margin-top: 10px;
}
</style>列表场景
模拟消息/文章列表骨架,多卡片各自扫光,观感接近真实页面。
查看源码
vue
<template>
<view class="list">
<ux-skeleton v-for="(item, index) in sceneList" :key="index" custom-class="list-item" avatar title :rows="3" :rows-width="['100%', '90%', '62%']" :rows-height="['16', '16', '16']" :title-width="'32%'" :title-height="'22'" />
</view>
</template>
<script setup lang="uts">
const sceneList = [1, 2, 3];
</script>
<style scoped>
.list {
display: flex;
flex-direction: column;
}
.list-item {
margin-bottom: 12px;
padding: 14px;
background-color: #ffffff;
border-radius: 8px;
}
</style>加载完成 loading
loading=false 时隐藏骨架,显示真实内容;骨架结构与真实内容一一对应,加载后原位替换。
查看源码
vue
<template>
<ux-skeleton :loading="loading" title avatar :rows="3" :rows-height="['18', '18', '40']" :title-height="'22'">
<view class="card">
<view class="card__avatar"></view>
<view class="card__body">
<text class="card__title">uView Pro 组件库</text>
<text class="card__line">丰富的组件覆盖开发过程各类需求,多端兼容,开箱即用。</text>
<text class="card__line">组件功能完善,样式与全局主题均支持自定义。</text>
<text class="card__line">示例代码一键复制,快速集成进你的项目。</text>
</view>
</view>
</ux-skeleton>
<view class="wrap">
<ux-button :type="loading ? 'primary' : 'default'" shape="round" @click="loading = !loading">{{ loading ? '切换加载中' : '加载完成' }}</ux-button>
</view>
</template>
<script setup lang="uts">
const loading = ref<boolean>(true);
</script>
<style scoped>
.wrap {
display: flex;
flex-direction: row;
margin-top: 10px;
}
.card {
display: flex;
flex-direction: row;
align-items: flex-start;
width: 100%;
padding: 12px;
background-color: #ffffff;
border-radius: 8px;
}
.card__avatar {
width: 40px;
height: 40px;
border-radius: 50%;
background-color: #2979ff;
margin-right: 12px;
flex-shrink: 0;
}
.card__body {
display: flex;
flex-direction: column;
justify-content: center;
flex: 1;
}
.card__title {
font-size: 16px;
font-weight: bold;
color: #323233;
margin-bottom: 8px;
}
.card__line {
font-size: 13px;
line-height: 20px;
color: #606266;
margin-bottom: 4px;
}
</style>API
Props
| 属性 | 说明 | 类型 | 默认值 | 版本 |
|---|---|---|---|---|
customStyle | 自定义根节点样式 | string | UTSJSONObject | - | - |
customClass | 自定义根节点样式类 | string | '' | - |
loading | 是否显示骨架占位图 | boolean | true | - |
animate | 是否开启动画效果 | boolean | true | - |
rows | 段落占位图行数 | string | number | 0 | - |
rowsWidth | 段落占位图的宽度 | string | number | string[] | '100%' | - |
rowsHeight | 段落的高度 | string | number | string[] | 18 | - |
title | 是否展示标题占位图 | boolean | true | - |
titleWidth | 标题的宽度 | string | number | '50%' | - |
titleHeight | 标题的高度 | string | number | 18 | - |
avatar | 是否展示头像占位图 | boolean | false | - |
avatarSize | 头像占位图大小 | string | number | 32 | - |
avatarShape | 头像占位图的形状 | string | 'circle' | - |
Events
ux-skeleton 无事件。
Slots
| 插槽名 | 说明 | 版本 |
|---|---|---|
default | loading=false 时展示的真实内容 | - |
注意事项
loading=false时才渲染默认插槽内容;骨架与真实内容需自行保持结构一致,否则切换时会跳动。rows-width/rows-height传数组时按行索引取值;数组长度不足时,宽度最后一行取 70%、其余 100%,高度统一取 18。animate仅在loading=true时可见;扫光在每个占位块内裁剪(overflow: hidden),不会铺到块间空隙。- App 端不使用
@keyframes,扫光由UniElement.animate逐条驱动,且linear-gradient仅支持方向 + 两色,渐变较 H5 / 小程序更简单。 avatar-shape支持circle(默认)与square(4px 小圆角)。