实现一个vue3组件库 - skeleton骨架屏
pid: 109441068
前言
骨架屏的实现思路大致有三种:
- 手动维护骨架屏的代码
- 使用图片作为骨架屏
- 自动生成骨架屏
这里的骨架屏指第一种。最终实现效果移步:Skeleton 骨架屏 | SSS UI Plus
骨架屏不会涉及很多逻辑代码,倒是css很有意思。
实现
骨架屏分为skeleton
、skeletonItem
两个组件。所有骨架屏Item都应该是一个普通的矩形盒子, 通过css样式来改变外观和布局。
skeleton
最外层skeleton
应该具有两个槽,一个作为真实UI, 一个作为骨架屏。且需要一个props属性来控制显示两者其一(props:loading).
code链接: sss-ui-plus/packages/SSkeleton
如何控制skeletonItem组件只能作用于skeleton组件内部呢?
通过vue3提供的provide
inject
, 在skeleton中provide某个变量, 在skeletonItem中inject这个变量,当skeletonItem没有接收到此变量时,抛出异常即可。
provide('hasSkeletonAnimation', props.animated)
provide('isWithinSkeleton', true)
如何控制在skeleton slot 和 真实UI slots之间切换时延时?
通过内部_loading属性控制显示哪一个slot, _loading属性受控于props.loading属性, 当props.loading属性切换为true时,延时一段时间后再设置_laoding变为true即可。
let timer: NodeJS.Timeout;
const _loading = ref<Boolean>(props.loading);
watch(() => props.loading, () => {
clearTimeout(timer); //注意要清除定时器
if (props.loading) {
_loading.value = true;
} else {
timer = setTimeout(() => {
_loading.value = false;
}, props.throttle);
}
})
skeletonItem(主要)
code链接: sss-ui-plus/packages/SSkeletonItem
首先是skeletonItem的结构:
<template>
<div
ref="item"
class="sss-skeleton-item"
:class="[{
'is-circle':props.isCircle,
'is-round':props.isRound,
'animated':animated,
},
`sss-skeleton-item-image`
]"
>
<svg v-if="props.type === 'image'" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg">
<path fill="currentColor"
d="M96 896a32 32 0 0 1-32-32V160a32 32 0 0 1 32-32h832a32 32 0 0 1 32 32v704a32 32 0 0 1-32 32H96zm315.52-228.48-68.928-68.928a32 32 0 0 0-45.248 0L128 768.064h778.688l-242.112-290.56a32 32 0 0 0-49.216 0L458.752 665.408a32 32 0 0 1-47.232 2.112zM256 384a96 96 0 1 0 192.064-.064A96 96 0 0 0 256 384z"></path>
</svg>
</div>
</template>
这里如果类型是image,采用了element plus的一个svg图标
部分样式文件:
.sss-skeleton-item{
//省略了部分样式
&.animated {
//使用扫描线
.useBGScanningLine(var(--sss-color-gray-deep-fade));
}
}
扫描线动画
采用的是less的混合函数
.useBGScanningLine (@bgColor){
background: linear-gradient(
100deg,
rgba(255, 255, 255, 0) 30%,
rgba(255, 255, 255, .5) 50%,
rgba(255, 255, 255, 0) 70%
) @bgColor;
background-size: 200% 100%;
background-position-x: 180%;
animation: 1.2s __bgLine linear infinite;
}
@keyframes __bgLine {
to {
background-position-x: -20%;
}
}
现在我们一项项分析
首先准备一个demo:
<template>
<div class="demo"></div>
</template>
<style lang="less">
@import "src/styles/global";
.demo{
height: 40px;
width: 600px;
.useBorderGray();
.useBorderRadius7px();
}
</style>
background
属性使用了linear-gradient
线性渐变时:
background: linear-gradient(
red, silver //由于是线性渐变,所以至少要两个颜色
);
可以观察到默认是向下渐变
现在我们设置渐变方向,并且设置不同颜色的占比。
background: linear-gradient(
100deg, //表示以数学中的坐标系的y负轴为参考,逆时针转100度
red 40%,
silver 50%,
red 60%
);
可以观察到这时在40%-60%之间出现了一条线
当背景颜色不存在(透明)时,显示背景基色
在上面代码中我们都没设置颜色的透明度和背景基色,代码修改如下
background: linear-gradient(
100deg,
rgba(255,0,0,0.5) 40%,
silver 50%,
rgba(255,0,0,0.5) 60%
) black;
可以观察到红色背景透明时会显示出背景基色(黑色);
background-position-x 如其名,用于设置背景的x偏移量:
height: 40px;
width: 600px;
.useBorderGray();
.useBorderRadius7px();
background: linear-gradient(
100deg,
rgba(255,0,0,0.5) 40%,
silver 50%,
rgba(255,0,0,0.5) 60%
) black;
background-position-x: 180%;
你会观察到背景没有任何变化,为什么?
因为背景默认会占满整个盒子,也就是背景的大小 === 盒子大小,此时你设置偏移量不会起作用。当我们放大背景时,偏移量就起作用了。
height: 40px;
width: 600px;
.useBorderGray();
.useBorderRadius7px();
background: linear-gradient(
100deg,
rgba(255,0,0,0.5) 40%,
silver 50%,
rgba(255,0,0,0.5) 60%
) black;
background-size: 200% 100%;
background-position-x: 10%;
background-position-x: 20%;
background-position-x: 30%;
此时你会发现,偏白色区域会随着background-position-x属性而变化!
此时我们给他运用一个动画就行实现扫描线的效果了!
.demo{
height: 40px;
width: 600px;
.useBorderGray();
.useBorderRadius7px();
background: linear-gradient(
100deg,
rgba(255,0,0,0.5) 40%,
silver 50%,
rgba(255,0,0,0.5) 60%
) black;
background-size: 200% 100%;
background-position-x: 180%;
animation: 1.2s __bgLine linear infinite;
}
@keyframes __bgLine {
to {
background-position-x: -20%;
}
}
需要注意的是,background-position-x需要根据需要进行微调.
最后把它封装为一个less混合函数:
.useBGScanningLine (@bgColor){
background: linear-gradient(
100deg,
rgba(255, 255, 255, 0) 30%,
rgba(255, 255, 255, .5) 50%,
rgba(255, 255, 255, 0) 70%
) @bgColor;
background-size: 200% 100%;
background-position-x: 180%;
animation: 1.2s __bgLine linear infinite;
}
写在最后
这个组件也许有很多不完善的地方,欢迎指出!
这个项目的地址是:lastertd/sss-ui-plus: 适用于vue3的组件库 (github.com)在这里求一个star✨
感谢看到最后💟💟💟
转载自:https://juejin.cn/post/7267948449966276671