Skip to content

Skeleton 骨架屏

iPhone

此组件一般用于页面在请求远程数据尚未完成时,页面用灰色块预显示本来的页面结构,给用户更好的体验。

平台差异说明

APPH5微信小程序支付宝小程序QQ小程序···
适配中

代码示例

部分功能示例,具体可参考示例程序以及文档API。

基础用法

此组件主要由 loadingskeleton 两个属性控制,骨架屏的具体内容由 skeleton 中的属性决定,这点很重要,理论上只需要按照约定配置好此参数,就可以实现想要的结构

  • 通过 loading 属性(必选),控制是否加载中状态,如果为 true 显示骨架屏组件占位,否则显示插槽中的内容
  • 通过 skeleton 属性,数组形式[Object, Object, ...]
    1. Object.type类型,type的类型有多种,详见下方参数说明,实际上type的意义并不大,除了flex类型外(下面单独说明该用法),其他的类型都可以自定义任意样式,默认 line
    2. Object.num 表示重复数量,默认 1
    3. Object.gap重复数量之间的垂直间隔,只有Object.num大于1时才生效,默认 20rpx
html
<template>
    <view>
        <fu-skeleton :loading="loading" :skeleton="skeleton"></fu-skeleton>
    </view>
</template>

<script setup>
    import { ref } from 'vue';

    // data数据
    let loading = ref(true);
    let skeleton = [
        { type: 'line', num: 3, gap: '20rpx' }
    ];
</script>

设置自定义样式

通过 skeleton 属性中的 style 属性,可以自定义样式,具体用法如下:

  • style 的类型可以是 arraystringobject,示例中的演示代码都有体现,样式根据需求自定义
  • stylearray 类型,例:['height: 25rpx;', null, null],代表第一个line高度为25rpx,其余的line使用默认样式
  • stylestringobject 类型,实际上都是一样的,都是设置了3个line均使用设置的样式
html
<template>
    <view>
        <fu-skeleton :loading="loading" :skeleton="skeleton"></fu-skeleton>
    </view>
</template>

<script setup>
    import { ref } from 'vue';

    // data数据
    let loading = ref(true);
    let skeleton = [
        { 
            type: 'line', 
            num: 3, 
            gap: '20rpx',
            style: ['width: 100rpx; marginBottom: 20rpx;', 'height: 25rpx;', 'width: 200rpx;'],
            // style: 'width: 100rpx; marginBottom: 20rpx;'
            // style: {width: '100rpx', marginBottom: '20rpx'}
        }
    ];
</script>

设置横向并列布局

通过 skeleton 属性中的 flex 属性,可以设置横向并列布局

  • Object.children 此属性的用法与上述一致,注意:children下不支持再有children
  • type 还有 avatarcoustom 类型
    1. avatar 类型,为了更好理解,增加了头像类型,有自己的默认样式,实际上也可以使用style进行样式自定义
    2. coustom 类型,如果完全自定义样式的可以使用此类型
html
<template>
    <view>
        <fu-skeleton :loading="loading" :skeleton="skeleton"></fu-skeleton>
    </view>
</template>

<script setup>
    import { ref } from 'vue';

    // data数据
    let loading = ref(true);
    let skeleton = [
        { 
            type: 'flex', 
            num: 1,
            children: [
                { type: 'avatar', num: 1, style: 'marginRight: 20rpx;' },
                { type: 'line', num: 2, style: ['width: 100rpx;'null, 'width: 200rpx;'] }
                { type: 'custom', num: 1, style: 'width: 100rpx; height: 200rpx; marginLeft: 20rpx;' }
            ]
        }
    ];
</script>

混合布局 + 插槽内容

  • 通过插槽传入展示的内容,当请求结束后,将 loading 属性设置为 false,此时会隐藏骨架屏组件,同时展示插槽中的内容
  • skeleton 属性还可以是 Number,表示上下之间的间距,单位为 rpx,25表示上下之间的间距为 25rpx
html
<template>
    <view class="custom-page">
        <fu-skeleton :loading="loading" :skeleton="skeleton" :animate="animate">
            <view class="skeleton-wrap__row">
                <view class="skeleton-wrap__row1--left">
                    <fu-image width="140rpx" height="140rpx" src="https://picsum.photos/65/65"></fu-image>
                </view>
                <view class="skeleton-wrap__row1--right">
                    <fu-text text="骨架屏" size="28rpx" lines="1"></fu-text>
                    <fu-text text="骨架屏一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。" size="28rpx" lines="1" margin="8rpx 0 0"></fu-text>
                    <fu-text text="提升用户视觉体验" lines="1" size="28rpx" margin="8rpx 0 0"></fu-text>
                </view>
            </view>
            <view class="skeleton-wrap__gap"></view>
            <view class="skeleton-wrap__row skeleton-wrap__between">
                <fu-image width="114rpx" height="180rpx" src="https://picsum.photos/114/180"></fu-image>
                <fu-image width="114rpx" height="180rpx" src="https://picsum.photos/115/180"></fu-image>
                <fu-image width="114rpx" height="180rpx" src="https://picsum.photos/116/180"></fu-image>
                <fu-image width="114rpx" height="180rpx" src="https://picsum.photos/117/180"></fu-image>
                <fu-image width="114rpx" height="180rpx" src="https://picsum.photos/118/180"></fu-image>
            </view>
            <view class="skeleton-wrap__gap"></view>
            <view class="skeleton-wrap__row">
                <view class="skeleton-wrap__row2--left">
                    <fu-text text="骨架屏一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。" size="28rpx" lines="1" bold></fu-text>
                    <fu-text text="骨架屏一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。" lines="1" size="28rpx" margin="8rpx 0 0"></fu-text>
                    <fu-text text="骨架屏一般用于页面在请求远程数据尚未完成时,在内容加载出来前展示与内容布局结构一致的灰白块,提升用户视觉体验。" lines="1" size="28rpx" margin="8rpx 0 0"></fu-text>
                </view>
                <view class="skeleton-wrap__row2--right">
                    <fu-image width="140rpx" height="140rpx" src="https://picsum.photos/180/180"></fu-image>
                </view>
            </view>
        </fu-skeleton>
    </view>
</template>

<script setup>
    import { ref } from 'vue';

    // data数据
    const loading = ref(true);
    const animate = ref(true);
    const skeleton = [
        { type: 'flex', num: 1, children: [{
                type: 'custom',
                num: 1,
                style: 'width: 140rpx; height: 140rpx; marginRight: 30rpx;'
            }, {
                type: 'line',
                num: 3,
                style: [null, 'width: 360rpx;', 'width: 200rpx;']
            }]
        }, 25, 
        { type: 'flex', children: [{
                type: 'custom',
                style: 'width: 114rpx; height: 180rpx;'
            }, {
                type: 'custom',
                style: 'width: 114rpx; height: 180rpx; marginLeft: 30rpx;'
            }, {
                type: 'custom',
                style: 'width: 114rpx; height: 180rpx; marginLeft: 30rpx;'
            }, {
                type: 'custom',
                style: 'width: 114rpx; height: 180rpx; marginLeft: 30rpx;'
            }, {
                type: 'custom',
                style: 'width: 114rpx; height: 180rpx; marginLeft: 30rpx;'
            }]
        }, 25, 
        { type: 'flex', children: [{
                type: 'line',
                num: 3,
                gap: '20rpx',
                style: [null, null, 'width: 400rpx;']
            }, {
                type: 'custom',
                style: 'width: 140rpx; height: 140rpx; marginLeft: 30rpx;'
            }],
        }
    ];
</script>

<style lang="scss" scoped>
    $coverSize: 140rpx;

    .skeleton-wrap {

        &__row {
            /* #ifndef APP-NVUE */
            display: flex;
            /* #endif */
            flex-direction: row;
       }

        &__row1 {

          &--left {
                width: $coverSize;
                height: $coverSize;
                margin-right: 30rpx;
           }

            &--right {
                flex: 1;
           }
       }

        &__row2 {

           &--left {
                flex: 1;
           }

            &--right {
                width: $coverSize;
                height: $coverSize;
                margin-left: 30rpx;
            }
        }

        &__between {
            justify-content: space-between;
        }

        &__gap {
            height: 25rpx;
        }
    }
</style>

API

Skeleton Props

属性名说明类型默认值可选值
loading是否显示骨架屏Booleantruefalse
animate是否开启动画Booleantruefalse
skeleton骨架屏配置项,具体用法详见下方Skeleton OptionsArray--

Skeleton Options

属性名说明
Object.type骨架类型,组件内置了四种:
line 段落结构
avatar 头像形状
flex 并列,需要有children属性
custom 自定义类型,理论上和line、avatar并没区别,但可以自定义样式都可以完全自定义样式
Object.num重复数量,[{type: 'line', num: 2}] 意思就是2个段落结构骨架
Object.gap骨架垂直间距,[{type: 'line', num: 2, gap: '20rpx'}]意思就是2个段落结构骨架的间距均为20rpx。注意:只有Object.num大于1生效
Object.style骨架样式,类型是Array/String/Object,Array依次对应重复骨架的样式,数组中也可以使用Object/String,Object/String表示重复的骨架均用此样式,详见下方设置自定义样式
Object.children子骨架,只有flex类型才有此属性,详见下方设置横向并列布局
Number表示数组上一项和下一项的间隔距离,单位 rpx。详见上方[混合布局 + 插槽内容](#混合布局 + 插槽内容)

Skeleton Slot

名称说明
default插槽内容,当请求结束后,将 loading 属性设置为 false,此时会隐藏骨架屏组件,同时展示插槽中的内容