阅读 236

vant加载组件不够用,那就手写一个loading组件

前言

  • 常网IT戳我呀!

  • 常网IT源码上线啦!

  • 如果是海迷,RED红发剧场版有需要可关注我主页公众号回“海贼王red”领取。

  • 已有专栏Vue、吊打面试官,各位看官感兴趣可移步????。

  • 最近在开发过程中,发现vant官网提供的组件不足以满足需求,所以手写一个Loading组件。


每个组件都有自己的出场机会。

1.jpg

一、存在问题

在实战开发中,vant作为移动端UI的一把手,想必我们都很熟悉。

1.1 需求

最近开发过程中,想实现接口请求中,展示全屏loading,接口请求回来,关闭全屏loading。

  • 覆盖全屏的loading加载

  • 通过JavaScript控制显示与否

1.2 Loading 加载

于是,我们翻了一下官方组件,发现vant提供了Loading加载组件。

组件似乎只适用于上拉下拉刷新,展示的加载状态❌。

而我们想要的是全屏的Loading,所以不太适用。

2.gif

1.3 Toast 轻提示

官方还提供Toast组件。

这个效果正是我们所想要的,通过JavaScript让其创建显示。

// 自定义加载图标  Toast.loading({     message: '加载中...',      forbidClick: true,      loadingType: 'spinner',  }); 复制代码

很可惜的一点是:官方并没有提供手动隐藏的API,只提供xxx毫秒后自动关闭。

也有可能有,但我没找到。

3.gif

既然官方提供的组件不合我意,那就手写一个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无限。

4.gif

加载是转圈的,那么可利用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 } 复制代码

看下效果。

5.png

一个简简单单的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。

还记得刚毕业那会,死记硬背下垂直居中的答案,如今,已经能够靠平时实践而回答。
背而不理解,无用。(但面试救救急该背还是得背????,日后慢慢实践理解即可)
唯有实践出真理。

五、其他加载效果

能不能再来亿点点,让项目经理选选。

16.jpeg

5.1

定义一个 div元素,设置边长为 40px 背景白色的正方形,然后设置循环翻转动画实现该加载效果动画。

perspective 属性定义 3D 元素距视图的距离。

6.gif

5.2

两个子元素 div 实现半透明的圆形,设置绝对定位重叠在一起,然后设置相同的动画通过不同的延迟时间交替放大缩小。

7.gif

5.3

在类名为 spinner元素下有五个 div 实现的长方形元素,设置Y轴的缩放,通过不同的延迟时间来达到依次变化的效果。

8.gif

5.4

两个子元素实现白色的方块,添加动画属性,在X轴和Y轴分别设置移动距离和缩放,通过不同的延迟时间来分离他们,rorate实现围绕中心旋转。

9.gif

5.5

两个实心圆形围绕中心做循环的缩放旋转运动,因为不同的延迟时间来达到它们同一时间呈现相反的表现。

10.gif

5.6

三个实色圆形横向排列,线性动画 scale从0到1,通过给它们不同的延迟时间,呈现依次交替的效果。

11.gif

5.7

整个加载效果由12个圆心组成,设置不同的旋转让它们呈现圆形环绕,然后设置不同的延迟时间,让它们做缩放运动。

12.gif

5.8

九个方块通过 grid布局,形成横向纵向分别三块,设置不同的延迟时间让它们做线性 3D 缩放运动。

13.gif

5.9

四个等边方块形成一个正方形,整个旋转45度,然后每个方块通过不同的延迟时间,沿X轴做翻转动画。设置perspective是为了有3D的效果。

14.gif

以上例子都放在Github,点我下载????

后记

以上的这些案例原理都是通过不同的延迟时间,给元素或子元素设置包括X、Y和Z轴上的移动旋转,以及缩放来达到动画的效果。

17.jpeg

虽然我们看到正在loading中会很烦,我这暴脾气,但却是交互中必不可少的良好体验。

我是Dignity_呱,如果想跟我一起讨论和学习前端可以关注我深夜末班车,咱们交朋友,一起进步。


作者:Dignity_呱
链接:https://juejin.cn/post/7169012607364366373

文章分类
代码人生
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐