vant加载组件不够用,那就手写一个loading组件
前言
常网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组件便大功告成。
Loading组件已放在Github,点我下载????
四、水平垂直居中
我们在上面有说到加载效果要在屏幕的居中显示。
那顺便来道经典的面试题,如何实现水平垂直居中?
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;
不过这个一定要熟知原理才能用得顺手,建议看下vertical-align和line-height的基友关系 ;然后便是绝对定位,虽然代码多了点,但是胜在适用于不同情况;
移动端兼容性允许的情况下能用
flex
就用flex
4.5.3 水平垂直居中
一般情况下,水平垂直居中,我们最常用的就是绝对定位加负边距了,缺点就是需要知道宽高,使用transform倒是可以不需要,但是兼容性不好(ie9+);
其次就是绝对居中,绝对定位设置top、left、right、bottom为0,然后margin:auto; 让浏览器自动平分边距以达到水平垂直居中的目的;
如果是行内/行内块级/图片这些内容,可以优先考虑line-height和vertical-align 结合使用,不要忘了还有text-align ,这个方法代码其实不多,就是理解原理有点困难,想要熟练应对各种情况还需好好研究;
移动端兼容性允许的情况下能用flex就用flex。
还记得刚毕业那会,死记硬背下垂直居中的答案,如今,已经能够靠平时实践而回答。
背而不理解,无用。(但面试救救急该背还是得背????,日后慢慢实践理解即可)
唯有实践出真理。
五、其他加载效果
能不能再来亿点点,让项目经理选选。
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的效果。
以上例子都放在Github,点我下载????
后记
以上的这些案例原理都是通过不同的延迟时间,给元素或子元素设置包括X、Y和Z轴上的移动旋转,以及缩放来达到动画的效果。
虽然我们看到正在loading中会很烦,我这暴脾气,但却是交互中必不可少的良好体验。
我是Dignity_呱,如果想跟我一起讨论和学习前端可以关注我深夜末班车,咱们交朋友,一起进步。
作者:Dignity_呱
链接:https://juejin.cn/post/7169012607364366373