原因
前面数据懒加载中提到过,组件数据懒加载是进入到可视区才开始加载数据,如果用户滚动过快,数据还没加载回来,会有白屏的效果,因此需要使用骨架屏组件进行优化
步骤
- 需要一个组件,做占位使用。这个占位组件有个专业术语:骨架屏组件。
- 属性:高,宽,背景,是否有闪动画,是否有淡入淡出动画。
- 这是一个公用组件,需要全局注册,将来这样的组件建议在vue插件中定义。
- 使用组件完成左侧分类骨架效果。
1.搭建静态骨架屏组件
在src/components/Skeleton/Skeleton.vue
<!-- //骨架组件 -->
<!-- 先写个死的,再改成活的 -->
<template>
<div
class="skeleton shan fade"
style="width:300px;height:50px;"
>
<!-- 1 盒子-->
<div class="block" :style="{ backgroundColor: '#ccc' }">
</div>
<!-- 2 闪效果 skeleton 伪元素 --->
</div>
</template>
<style scoped lang="less">
.skeleton {
display: inline-block;
position: relative;
overflow: hidden;
vertical-align: middle;
.block {
width: 100%;
height: 100%;
border-radius: 2px;
}
}
.shan {
&::after {
content: '';
position: absolute;
animation: shan 1.5s ease 0s infinite;
top: 0;
width: 50%;
height: 100%;
background: linear-gradient(
to left,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.3) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: skewX(-45deg);
}
}
@keyframes shan {
0% {
left: -100%;
}
100% {
left: 120%;
}
}
.fade {
animation: fade 1s linear infinite alternate;
}
@keyframes fade {
from {
opacity: 0.2;
}
to {
opacity: 1;
}
}
</style>
小结
fade:淡入淡出的效果 animated:动画
定义props接收
最终代码如下
<!-- //骨架组件 -->
<!-- 先写个死的,再改成活的 -->
<script setup lang="ts">
// 定义props接收
const {bg='green', animated=false, fade=false} = defineProps<{
width: number,
height: number,
bg?: string,
animated?: boolean,
fade?: boolean,
}>()
</script>
<template>
<div
class="skeleton"
:class="{shan:animated, fade}"
:style="{width:width+'px', height:height+'px'}"
>
<!-- 1 盒子-->
<div class="block" :style="{ backgroundColor:bg }">
</div>
<!-- 2 闪效果 skeleton 伪元素 --->
</div>
</template>
<style scoped lang="less">
.skeleton {
display: inline-block;
position: relative;
overflow: hidden;
vertical-align: middle;
.block {
width: 100%;
height: 100%;
border-radius: 2px;
}
}
.shan {
&::after {
content: '';
position: absolute;
animation: shan 1.5s ease 0s infinite;
top: 0;
width: 50%;
height: 100%;
background: linear-gradient(
to left,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.3) 50%,
rgba(255, 255, 255, 0) 100%
);
transform: skewX(-45deg);
}
}
@keyframes shan {
0% {
left: -100%;
}
100% {
left: 120%;
}
}
.fade {
animation: fade 1s linear infinite alternate;
}
@keyframes fade {
from {
opacity: 0.2;
}
to {
opacity: 1;
}
}
</style>
2.骨架组件-改进左侧分类
在分类组件中使用骨架屏组件
src/views/My/components/MyCate.vue
<template v-if="item.children">
<RouterLink
:to="`/cate/sub/${sub.id}`"
:key="sub.id"
v-for="sub in item.children?.slice(0, 2)"
>
{{ sub.name }}
</RouterLink>
</template>
<template v-else>
<Skeleton
:width="60"
:height="18"
style="margin-right: 5px"
bg="rgba(255,255,255,0.2)"
animated
/>
<Skeleton
:width="50"
:height="18"
bg="rgba(255,255,255,0.2)"
animated
/>
</template>
3.骨架组件-全局注册(插件)
全局组件的基本使用
const app = createApp(App)
app.component('组件名',组件对象)
在v2 是 Vue.component('组件名',组件对象)
v2中插件 Vue.use
全局组件的使用-插件
就是使用app.use
整体实现步骤
1.新建文件 components/index.ts
// 统一的注册所有的全局组件
import Skeleton from '@/components/Skeleton/Skeleton.vue'
// App 是在vue库中定义好的类型
import { App } from 'vue'
export default {
install (app: App) {
app.component('Skeleton', Skeleton)
}
}
2.在main.ts中全局注册
import Cart from './components'
const app = createApp(App)
app.use(Cart)
在vue3中如果注册的是局部组件,那么props是有类型提示的,但是如果注册的是全局组件,props就没有类型提示了
这时,应该在src目录下新建一个文件 global.d.ts
import Skeleton from '@/components/Skeleton/Skeleton.vue'
// 参考:
declare module 'vue' {
export interface GlobalComponents {
Skeleton: typeof Skeleton
}
}
export {}
在TS中定义了全局组件,有固定的套路让它具备提示效果