Skeleton
17:06Description
A placeholder skeleton shown while data loads. With loading=true it renders gray blocks per avatar / title / rows; with loading=false it renders the real content from the default slot, replacing in place; animate controls the per-block shimmer.
Compatibility
| Platform | Support |
|---|---|
| App | ✅ Supported (shimmer is driven by UniElement.animate per block, with a simplified two-stop gradient) |
| H5 | ✅ Supported (shimmer is driven by CSS @keyframes) |
| WeChat Mini Program | ✅ Supported (shimmer is driven by CSS @keyframes) |
Examples
Basic Usage
Shows title and paragraph placeholders by default when loading=true.
View source
<template>
<ux-skeleton :loading="true" :rows="3" />
</template>Rows (rows)
Set the number of paragraph placeholder rows via rows.
View source
<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>Custom Width/Height
rows-width / rows-height support arrays per row; title-width / title-height set the title size.
View source
<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)
avatar=true shows an avatar placeholder; avatar-shape supports circle / square.
View source
<template>
<ux-skeleton :loading="true" :rows="3" avatar :avatar-size="20" avatar-shape="circle" />
</template>Animation Toggle (animate)
animate controls the shimmer sweep; toggle the button to compare on/off.
View source
<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>List Scene
Simulates message/article list skeletons; each card shimmers independently for a realistic look.
View source
<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>Loaded (loading)
loading=false hides the skeleton and shows real content; the skeleton structure matches the real content one-to-one and replaces it in place.
View source
<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
| Property | Description | Type | Default | Version |
|---|---|---|---|---|
customStyle | Custom root element style | string | UTSJSONObject | - | - |
customClass | Custom root element style class | string | '' | - |
loading | Whether to show the skeleton placeholders | boolean | true | - |
animate | Whether to enable the shimmer animation | boolean | true | - |
rows | Number of paragraph placeholder rows | string | number | 0 | - |
rowsWidth | Width of the paragraph placeholders | string | number | string[] | '100%' | - |
rowsHeight | Height of the paragraph placeholders | string | number | string[] | 18 | - |
title | Whether to show the title placeholder | boolean | true | - |
titleWidth | Width of the title | string | number | '50%' | - |
titleHeight | Height of the title | string | number | 18 | - |
avatar | Whether to show the avatar placeholder | boolean | false | - |
avatarSize | Size of the avatar placeholder | string | number | 32 | - |
avatarShape | Shape of the avatar placeholder | string | 'circle' | - |
Events
ux-skeleton has no events.
Slots
| Slot | Description | Version |
|---|---|---|
default | Real content shown when loading=false | - |
Notes
- The default slot is rendered only when
loading=false; keep the skeleton and the real content structurally consistent, or the switch will jump. - When
rows-width/rows-heightare arrays they are read by row index; if the array is shorter, the width falls back to 70% for the last row and 100% for the rest, and the height falls back to 18. animateis only visible whileloading=true; the shimmer is clipped inside each placeholder block (overflow: hidden) and does not bleed into the gaps between blocks.- On App,
@keyframesis not used — the shimmer is driven byUniElement.animateper block, andlinear-gradientonly supports a direction plus two colors, so the gradient is simpler than on H5 / Mini Program. avatar-shapesupportscircle(default) andsquare(a 4px small radius).