theme: fancy
highlight: arduino-light
本文正在参加「金石计划 . 瓜分6万现金大奖」
前言
- 常网IT戳我呀!
- 常网IT源码上线啦!
- 如果是海迷,RED红发剧场版有需要可关注我主页公众号回“海贼王red”领取。
- 已有专栏Vue、吊打面试官,各位看官感兴趣可移步🚶。
- 最近在开发过程中,发现vant官网提供的组件不足以满足需求,所以手写一个Loading组件。
每个组件都有自己的出场机会。
一、存在问题
在实战开发中,vant作为移动端UI的一把手,想必我们都很熟悉。
1.1 需求
最近开发过程中,想实现接口请求中,展示全屏loading,接口请求回来,关闭全屏loading。
-
覆盖全屏的loading加载
-
通过JavaScript控制显示与否
1.2 Loading 加载
于是,我们翻了一下官方组件,发现vant提供了Loading
加载组件。
组件似乎只适用于上拉下拉刷新,展示的加载状态❌。
而我们想要的是全屏的Loading,所以不太适用。
1.3 Toast 轻提示
官方还提供Toast组件。
这个效果正是我们所想要的,通过JavaScript让其创建显示。
// 自定义加载图标
Toast.loading({
message: '加载中...',
forbidClick: true,
loadingType: 'spinner',
});
很可惜的一点是:官方并没有提供手动隐藏的API,只提供xxx毫秒后自动关闭。
也有可能有,但我没找到。
既然官方提供的组件不合我意,那就手写一个Loading加载组件吧!
二、Loading组件诞生
html结构如下:
<template>
<div>
<div class="load">
<!-- 中间的图案动效加载 -->
<div class="sk-chase"></div>
<!-- 文字加载 -->
<span>加载中...</span>
</div>
<!-- 全屏遮罩层 -->
<div class="full-screen"></div>
</div>
</template>
我们的class:full-screen
作为全屏的遮罩层,定位应是fixed固定定位,防止页面滑动上下滚动而下层无法遮罩。
class:load
作为中间的动效加载,定位也应是fixed
固定定位,屏幕居中,我们设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 translate 来调整子元素的中心点到父元素的中心。该方法可以不定宽高。
class:sk-chase
作为中间的图案动效加载,既然是动效,那离不开我们的animation
,设置为infinite无限。
加载是转圈的,那么可利用rotate(360deg)
而且我们的加载过程中大小会时大时小,可利用scale(0.4)
-> scale(1)
三、代码如下
Loading.vue
<!--
* @Description: Load加载 -- 组件
-->
<template>
<div>
<div class="load">
<!-- 中间的图案动效加载 -->
<div class="sk-chase">
<div class="sk-chase-dot" v-for="(item, key) in 6" :key="key"></div>
</div>
<!-- 文字加载 -->
<span>{{ title }}</span>
</div>
<!-- 全屏遮罩层 -->
<div class="full-screen"></div>
</div>
</template>
<script>
export default {
name: "loading",
props: {
title: {
type: String,
default: "加载中...",
},
},
data() {
return {};
},
};
</script>
<style scoped="scoped" lang="scss">
.full-screen {
position: fixed;
overflow: hidden;
left: 0;
top: 0;
background: rgba(255, 255, 255, 0.3);
width: 100%;
height: 100%;
z-index: 1;
}
.load {
color: #dfdfdf;
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 120px;
height: 120px;
border-radius: 8px;
background: rgba(74, 74, 74, 0.9);
z-index: 2;
span {
position: absolute;
bottom: 15%;
left: 25%;
}
}
.sk-chase {
width: 40px;
height: 40px;
position: absolute;
top: 20px;
left: 35%;
animation: sk-chase 2.5s infinite linear both;
}
.sk-chase-dot {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
animation: sk-chase-dot 2s infinite ease-in-out both;
}
.sk-chase-dot:before {
content: "";
display: block;
width: 25%;
height: 25%;
background-color: #dfdfdf;
border-radius: 100%;
animation: sk-chase-dot-before 2s infinite ease-in-out both;
}
.sk-chase-dot:nth-child(1) {
animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2) {
animation-delay: -1s;
}
.sk-chase-dot:nth-child(3) {
animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4) {
animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5) {
animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6) {
animation-delay: -0.6s;
}
.sk-chase-dot:nth-child(1):before {
animation-delay: -1.1s;
}
.sk-chase-dot:nth-child(2):before {
animation-delay: -1s;
}
.sk-chase-dot:nth-child(3):before {
animation-delay: -0.9s;
}
.sk-chase-dot:nth-child(4):before {
animation-delay: -0.8s;
}
.sk-chase-dot:nth-child(5):before {
animation-delay: -0.7s;
}
.sk-chase-dot:nth-child(6):before {
animation-delay: -0.6s;
}
@keyframes sk-chase {
100% {
transform: rotate(360deg);
}
}
@keyframes sk-chase-dot {
80%,
100% {
transform: rotate(360deg);
}
}
@keyframes sk-chase-dot-before {
50% {
transform: scale(0.4);
}
100%,
0% {
transform: scale(1);
}
}
</style>
于是我们在外层引入Loading.vue组件。
<Loading v-show="fullscreenLoading" title="提交中..." />
async getData(){
this.fullscreenLoading = true
const res = await get()
this.fullscreenLoading = false
}
看下效果。
一个简简单单的Loading组件便大功告成。
四、水平垂直居中
我们在上面有说到加载效果要在屏幕的居中显示。
那顺便来道经典的面试题,如何实现水平垂直居中?
4.1 绝对定位(left、top50%、translate)
利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 translate 来调整子元素的中心点到父元素的中心。该方法可以不定宽高。
注意这里启动了3D硬件加速哦 会增加耗电量的。
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
/*
自身宽度一半,等同于margin-left: -50px; 等同于margin-top: -50px;
想想如不设置transform偏移的话,son元素整体会向右下
因为没有减掉son元素自身的宽高呀
*/
}
父相re子绝ab。
4.2 绝对定位(全部方向0、margin: auto)
利用绝对定位,子元素所有方向都为 0 ,将 margin 设置为 auto ,由于宽高固定,对应方向实现平分,该方法必须盒子有宽高。
.father {
position: relative;
}
.son {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0px;
margin: auto;
height: 100px;
width: 100px;
}
4.3 绝对定位(l、t50%、m-t-l宽高一半)
利用绝对定位,设置 left: 50% 和 top: 50% 现将子元素左上角移到父元素中心位置,然后再通过 margin-left 和 margin-top 以子元素自己的一半宽高进行负值赋值。该方法必须定宽高。
感觉看了圣杯模式的视频,现在看margin负值觉得很简单、好理解了😁。
关于圣杯模式、两栏布局后期出篇文章。
.father {
position: relative;
}
.son {
position: absolute;
left: 50%;
top: 50%;
width: 200px;
height: 200px;
margin-left: -100px;
margin-top: -100px;
}
4.4 flex横扫千军
利用 flex ,最经典最方便的一种了,不用解释,定不定宽高无所谓的。
其实还有很多方法,比如 display: grid 或 display: table-cell 来做,有兴趣点击下面这篇文章可以了解下:你能实现多少种水平垂直居中的布局(定宽高和不定宽高)。
.father {
display: flex;
justify-content: center;
align-items: center;
}
4.5 总结
4.5.1 水平居中
- 对于水平居中,我们应该先考虑,哪些元素有自带的居中效果,最先想到的应该就是
text-align:center
了,但是这个只对行内内容有效,所以我们要使用 text-align:center 就必须将子元素设置为 display: inline; 或者 display: inline-block; ; - 其次就是考虑能不能用
margin: 0 auto;
因为这都是一两句代码能搞定的事,实在不行就是用绝对定位去实现了。 - 移动端能用
flex
就用flex,简单方便,灵活并且功能强大,无愧为网页布局的一大利器!
4.5.2 垂直居中
- 对于垂直居中,最先想到的应该就是
line-height
了,但是这个只能用于行内内容; - 其次就是考虑能不能用
vertical-align: middle;
不过这个一定要熟知原理才能用得顺手,建议看下5.1
定义一个
div
元素,设置边长为 40px 背景白色的正方形,然后设置循环翻转动画实现该加载效果动画。perspective 属性定义 3D 元素距视图的距离。
5.2
两个子元素 div 实现半透明的圆形,设置绝对定位重叠在一起,然后设置相同的动画通过不同的延迟时间交替放大缩小。
5.3
在类名为
spinner
元素下有五个 div 实现的长方形元素,设置Y轴的缩放,通过不同的延迟时间来达到依次变化的效果。5.4
两个子元素实现白色的方块,添加动画属性,在X轴和Y轴分别设置移动距离和缩放,通过不同的延迟时间来分离他们,
rorate
实现围绕中心旋转。5.5
两个实心圆形围绕中心做循环的缩放旋转运动,因为不同的延迟时间来达到它们同一时间呈现相反的表现。
5.6
三个实色圆形横向排列,线性动画
scale
从0到1,通过给它们不同的延迟时间,呈现依次交替的效果。5.7
整个加载效果由12个圆心组成,设置不同的旋转让它们呈现圆形环绕,然后设置不同的延迟时间,让它们做缩放运动。
5.8
九个方块通过
grid
布局,形成横向纵向分别三块,设置不同的延迟时间让它们做线性 3D 缩放运动。5.9
四个等边方块形成一个正方形,整个旋转45度,然后每个方块通过不同的延迟时间,沿X轴做翻转动画。设置
perspective
是为了有3D的效果。后记
以上的这些案例原理都是通过不同的延迟时间,给元素或子元素设置包括X、Y和Z轴上的移动旋转,以及缩放来达到动画的效果。
虽然我们看到正在loading中会很烦,我这暴脾气,但却是交互中必不可少的良好体验。
我是Dignity_呱,如果想跟我一起讨论和学习前端可以关注我深夜末班车,咱们交朋友,一起进步。
👍 如果对您有帮助,您的点赞是我前进的润滑剂。
以往推荐
原文链接
暂无评论内容