loading随处可见,比如一个app经常会有下拉刷新,上拉加载的功能,在刷新和加载的过程中为了让用户感知到 load 的过程,我们会使用一些过渡动画来表达。最常见的比如“转圈圈”,“省略号”等等。
网页loading有很多用处,比如页面的加载进度,数据的加载过程等等,数据的加载loading很好做,只需要在加载数据之前(before ajax)显示loading效果,在数据返回之后(ajax completed)结束loading效果,就可以了。
首先准备一段loading的html:
|
|
样式装扮一下:
|
|
假设这个loading只需要在页面加载完成之后隐藏,中间不需要显示进度。那么很简单,我们第一时间想到的就是window.onload:
(以下内容为了方便演示,默认使用jQuery,语法有es6的箭头函数)
var $loading = $(‘#loading’)
var $progress = $(‘#progress’)
window.onload = () => {
$loading.hide()
}
效果不错,但是有个问题,万一window loaded太慢了,导致进度显示load到100%了,loading还没有隐藏,那就打脸了。所以,需要让loading在window loaded的时候才到达终点,在这之前,loading可以保持一个等待的状态,比如在80%的时候,先停一停,然后在loaded的时候快速将进度推至100%。这个做法是目前绝大部份进度条的做法。
|
|
ok,这差不多就是想要的功能了,重复的代码给封装一下:
|
|
得到了一个progress函数,这个函数就是我们主要的功能模块,通过传入一个目标值、一个时间间隔,就可以模拟进度的演化过程。
目前来看,这个进度还是有些问题的:
进度太平均,相同的时间间隔,相同的增量,不符合网络环境的特点;
window.onload太快,还来不及看清100%,loading就已经不见了;
每次第一阶段都是在80%就暂停了,露馅儿了;
第一个点,要让时间间隔随机,增量也随机;第二个点很简单,延迟一下就好了;第三点也需要我们随机产生一个初始值。
增量随机很好办,如何让时间间隔随机?setInterval是无法动态设置delay的,那么我们就要把它改造一下,使用setTimeout来实现。(setInterval跟setTimeout的用法和区别就不细说了吧?)
|
|
至此,差不多完成了需求。
but,还有一个比较隐蔽的问题,现在使用window.onload,发现从进入页面,到window.onload这中间相隔时间十分短,基本是感受不到第一阶段进度(80%)的,如果页面的加载资源数量很多,体积很大的时候,从进入页面,到window.onload就不是这么快速了,这中间可能会很漫长(5~20秒不等),但事实上,首屏资源 的加载争取时间就可以了,不需要等待所有资源就绪,而且更快地呈现页面也是提高用户体验的关键。
应该考虑页面loading停留过久的情况,需要为loading设置一个超时时间,超过这个时间,假设window.onload还没有完成,也要把进度推到100%,把loading结束掉。
|
|
直接设置了一个定时器,5s的时间来作为超时时间。这样做是可以的。
but,还是有问题,这个定时器是在js加载完毕之后才开始生效的,也就是说,忽略了js加载完毕之前的时间,这误差可大可小,设置的5s,实际用户可能等待了8s,这是有问题的。我们做用户体验,需要从实际情况去考虑,所以这个开始时间还需要再提前一些,我们在head里来记录这个开始时间,然后在js当中去做对比,如果时间差大于超时时间,那我们就可以直接执行最后的完成步骤,如果小于超时时间,则等待 剩余的时间 过后,再完成进度。
先在head里埋点,记录用户进入页面的时间loadingStartTime:
|
|
然后,对比 当前的时间 ,看是否超时:(为了方便复用代码,我把完成的部分封装成函数complete)
|
|
完整地实现了这一功能。
如果目的是为了写一个纯粹障眼法的伪loading,那跟其他loading的实现就没什么区别了,我们做事讲究脚踏实地,能实现的实现,不能实现的,为了团队和谐,我们不得已坑蒙拐骗。那么我们还能更贴近实际情况一点吗?其实是可以的。
来分析一个场景,假设让loading更加真实一些,那么可以选择性地对页面上几个比较大的资源的加载进行跟踪,然后拆分整个进度条,比如页面有三张大图a、b、c,那么将进度条拆成五段,每加载完一张图就推进一个进度:
随机初始化[10, 20] ->
图a推进20%的进度 ->
图b推进25%的进度 ->
图c推进30%的进度 ->
完成100%
这三张图要占20% + 25% + 30% = 75%的进度。
问题是,如果图片加载完成是按照顺序来的,那可以很简单地:10(假设初始进度是10%) -> 30 -> 55 -> 85 -> 100,但事实是,图片不会按照顺序来,谁早到谁晚到是说不准的,所以需要更合理的方式去管理这些进度增量,使它们不会互相覆盖。
需要一个能够累计增量的变量next;
由于progress都是传目的进度的,需要另外一个函数add,来传增量进度。
|
|
用setTimeout来模拟图片的加载,真实应用应该是使用image.onload。
以上,一步步实现一个进度loading的过程了,演示代码可以戳codePen 写一个网页进度loading。
看似很简单的一个功能,其实仔细推敲,还是有很多细节要考虑的。
到这里,其实真的已经完成了,
实现这个功能非常简单:
|
|
木油错,94这么简单!