微信小程序有自动做骨架屏的功能,uni-app貌似没看到,决定自己倒腾一个,上代码,先封一个skeleton组件
<template>
<div class="skeleton-comp">
<view v-for="(otem, idx) in skeletonRegion.skeletonRectLists" :key='idx' class="shine"
:style="{'width': `${otem.width}${unit}`, 'height': `${otem.height}${unit}`, 'left': `${otem.left}${unit}`, 'top': `${otem.top - topBoxHeight}${unit}`}">
</view>
<view v-for="(otem, idx) in skeletonRegion.skeletonCircleLists" :key='idx' class="shine flex-center-c circle-box bgc-fff"
:style="{'width': `${otem.width}${unit}`, 'height': `${otem.height}${unit}`, 'left': `${otem.left}${unit}`, 'top': `${otem.top - topBoxHeight}${unit}`}">
<view></view>
</view>
</div>
</template>
这里的style里面还要加一个position: absolute, 里面的这句- topBoxHeight是因为我的项目有做自定义header,需要把那个自定义盒子的高度去掉,如果不是自定义header,这里这一句就删掉,要不然算出来的高度不对。对哦,别忘了顶级的盒子要相对定位
接收两个props参数,selector决定用哪一个选择器,unit表示用什么单位
const props = defineProps({
selector: {
type: String,
default: 'skeleton'
},
unit: {
type: String,
default: 'px'
}
})
let skeletonRegion = ref({
skeletonRectLists: [],
skeletonCircleLists: []
})
let topBoxHeight = ref(getStorage('topBoxHeight'))
onMounted(() => {
rectHandle()
radiusHandle()
})
// 画矩形
const rectHandle = () => {
uni.createSelectorQuery().selectAll(`.${props.selector} >>> .${props.selector}-rect`).boundingClientRect().exec((res) => {
skeletonRegion.value.skeletonRectLists = res[0]
});
}
// 画圆形
const radiusHandle = () => {
uni.createSelectorQuery().selectAll(`.${props.selector} >>> .${props.selector}-radius`).boundingClientRect().exec((res) => {
skeletonRegion.value.skeletonCircleLists = res[0]
});
}
贴上css,做了一点动画效果,一步到位
.skeleton-comp{
position: relative;
@keyframes shine {
from {
background-position: 0 0 ;
}
to {
background-position: 20rem 0;
}
}
.shine {
background: rgb(194, 207, 214);
background-image: linear-gradient(90deg,rgba(255, 255, 255, 0.1) 20%, transparent 25%);
background-size: 20rem 20rem;
animation: shine 1s linear infinite;
position: absolute;
z-index: 999;
}
.wipe {
overflow: hidden;
margin: 0 auto;
display: inline-flex;
animation-name: wipe;
}
@keyframes wipe {
to { width: 0 }
}
.circle-box > view{
width: 100%;
height: 100%;
border-radius: 50%;
background: rgb(194, 207, 214);
background-image: linear-gradient(90deg,rgba(255, 255, 255, 0.1) 20%, transparent 25%);
background-size: 20rem 20rem;
animation: shine 1s linear infinite;
}
.bgc-fff{
background-color: #fff !important;
}
}
组件就封好了,具体咋用呢,当然是先引入组件,再用一个属性控制它的显示,后端数据加载成功后,隐藏这个骨架屏
import skeleton from '@/components/skeleton/skeleton.vue'
<skeleton selector="sk" v-if="showSkeleton"></skeleton>
重点来了,注意看这里的class具体咋写的,最外层盒子一定要有一个和你定义的selector值相同的class,然后里面的子盒子,你想画圆形的就用sk-radius,画矩形就用sk-rect
最后,因为这个组件是根据元素的宽高和定位画盒子的,所以必须要有原始的数据支撑盒子。要不然没宽高就gg
真正的大佬在这里github.com/jayZOU/skel…