Re从零开始的UI库编写生活之进度条组件

构想

一个网站若是想要提升用户体验,能够从提升使用流畅度,提升可用性,提升交互体验等等方向入手。其中认为网站应用的流畅度对提升用户体验来说是很关键的,可以在很大程度上对用户的心理预期做出及时的反馈。css

那么咱们就从一开始入手,去优化首屏加载的体验。据统计,若是首屏时间在2秒之内是能够算做优秀的,5秒之内是勉强能够接受的,5秒以上的话,大部分用户都会选择离开。想要优化首屏时间有不少方法,能够增长服务器资源,能够尽量压缩前端应用,或者部署到cdn上来缩减网站的响应时间,但不管如何,从用户发起请求到首屏加载完成这段时间,应用都是没法使用的,并且不少方法都须要有必定的成本。那究竟有没有一种通用的方法可以在不须要什么成本的状况下尽量缩短白屏时间呢?答案是有的,就是各类加载进度条,css加载动画和骨架屏。其中加载进度条很关键,除了能有效减小用户在等待白屏是的焦虑,还能提升应用总体衔接的流畅度。可以有效暗示用户的,给与一个心理期待,提高主观体验,让用户更愿意等待更长的时间。html

想要的效果

能根据网站的加载状况显示当前的加载进度。用户看到的白屏时间至多等于服务器响应时间加上index.html文件的加载时间,这个时间通常在1秒左右,index.html通常也只有几kb(千万别说把什么东西都往里放...)。前端

image

嗯,Demo就是SluckyUI首屏加载时的顶部加载进度条。git

总体结构

放置

为了尽量快地看到加载效果,缩短白屏时间,相关的功能代码应该直接加到index.html中,这样用户仅仅加载完index.html就能够看到加载进度条效果,同时功能代码尽量使用原生js编写。github

进度开始

咱们用一个自执行函数隔离做用域来做为加载进度条的开始web

// 相似于这样
(function(){
    updateProgress()
})()
复制代码

进度结束

监听浏览器的onload事件,当该页面的全部资源加载完成后,浏览器会触发onload事件,因此onload事件的发生能够做为整个加载过程的结束标志。sql

加载过程

重点来了,应该如何尽量真实地去记录加载的过程呢?嗯,咱们能够去逐个统计每一个资源的加载状况,而后转化为百分比显示到进度条上。nonono,这种方法除了能真的反映真实的加载状况外,就没什么优势了,通用性不够,精确去统计每一个资源很麻烦等等。。。npm

是的,因为每一个资源的大小数量不一,用户的加载速度又有差异,因此精确地计算页面的加载状况是一件很麻烦很头痛的事。这个时候应该剑走偏锋,施展一下前端的障眼法哈哈。在明确开始和结束的前提下,咱们就能够对加载过程进行模拟,即高仿,通常用户很难发现的那种高仿,会心一笑。后端

要作高仿的话有几个点很是重要浏览器

  • 进度条每次前进的距离要随机,咱们称为随机偏移量
  • 当进度条前进到某个点以后,就要适当停下来,等待真正的加载完成,防止还没加载完成,进度就走完的状况出现,同时也是为了防止真正的加载未完成,进度条就走完的状况发生。而这个定下来的时机固然也要随机。
  • 虽然关键节点都作成了随机,但具体的基准值须要视状况而定,每一个网站不必定同样,并且这些基础值的随机也要适当。

普通系列

根据上面的条件,咱们写出一个普通系列版本,各类参数都取固定值。

<!-- index.html -->
...
<progress max="100" value="0" class="progress-loading-g" id="progress_loading"></progress>
...
<script>
    (function(){
        var progress = document.getElementById('progress_loading')
        var _timer;
        
        updateProgress(100)
    
        // 加载结束后隐藏进度条
        window.onload = function() {
            progress.style.display = "none";
        }
        
        function updateProgress(target){
            // 边界条件判断一下
            if (target >= 100) {
                progress.value = 100;
                return;
            }
            _timer = setInterval(function() {
                // 未达到目标值时,进度进行累加
                if (progress.value < target) {
                    progress.value += 5;
                } else {
                    // 到达目标值,中止累加
                    progress.value = target;
                    clearInterval(_timer);
                }
            }, 0);
        }
    })()
</script>
...
复制代码

ok,并不困难,普通系列版本已经理清了大致思路,只是普通版本中那固定增长的进度很难欺骗用户的眼睛,那应该怎么作呢?

准备

接下来咱们要为认真系列作一些准备工做。 首先,每次增长的偏移量咱们要随机。

var _interval = Math.ceil(Math.random() * 5);
复制代码

每次到达的目标值也要随机,这个目标值一般在70%~90%之间,停下以后等待真正的加载完成。

// 咱们获得一个[-10,10]的区间,使得进度条能在目标值(±10)范围内停下
var isPositive = Math.floor(Math.random() * 2);
var tarOffset = Math.ceil(Math.random() * 10);
isPositive ? target += tarOffset : target -= tarOffset;
复制代码

onload事件触发后要等必定时间才让进度条消失,防止用户加载过快时进度条过早消失。

setTimeout(function() {
    progress.style.display = "none";
}, 3000);
复制代码

认真系列

<!-- index.html -->
...
<progress max="100" value="0" class="progress-loading-g" id="progress_loading"></progress>
...
<script>
    (function() {
            var $ = function(id) {
                return document.getElementById(id)
            }
            var progress = $('progress_loading');
            var _timer;
            var _disTimer;

            updateProgress(80, 300);

            function updateProgress(tar, delay, callback) {
                clearInterval(_timer);
                
                // 设置临界值
                if (tar >= 100) {
                    progress.value = 100;
                    clearInterval(_timer);
                    callback && callback();
                    return;
                }

                // 随机化到达的目标值
                var isPositive = Math.floor(Math.random() * 2);
                var tarOffset = Math.ceil(Math.random() * 10);
                isPositive ? tar += tarOffset : tar -= tarOffset;
                
                _timer = setInterval(function() {
                    if (progress.value < tar) {
                        // 随机化每次前进的偏移量
                        var _interval = Math.ceil(Math.random() * 5);
                        progress.value += _interval;
                    } else {
                        // 到达目标值,中止累加
                        progress.value = tar;
                        clearInterval(_timer);
                        callback && callback();
                    }
                }, delay);
            }
            // onload时间发生时即加载完成
            window.onload = function() {
                updateProgress(100, 0, function() {
                    clearTimeout(_disTimer);
                    // 防止用户加载过快时进度条过早消失
                    _disTimer = setTimeout(function() {
                        progress.style.display = "none";
                    }, 2000);
                });
            }
        })();
</script>
...
复制代码

好看的样式是必不可少的。

进度条样式

// index.html
...
<style>
    .progress-loading-g {
        display: block;
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 2px;
        background-image: linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55);
    }

    .progress-loading-g::-moz-progress-bar {
        background-image: linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55);
    }

    .progress-loading-g::-webkit-progress-bar {
        background-image: linear-gradient(to right, #4cd964, #5ac8fa, #007aff, #34aadc, #5856d6, #ff2d55);
    }

    .progress-loading-g::-webkit-progress-value {
        background: #fff;
        transition: all 1s;
    }
</style>
...
复制代码

Bingo!到此为止,一个高仿真的加载进度条就搞定了,将相关功能代码加入你的网站就能够有效提升总体的流畅度和用户体验,快快行动起来吧。记得不一样网站的状况不一样,根据状况能够微调进度条每次前进的偏移量和间隔时间。

附:加载进度条源码

更多有趣的进度条

image

Demo和使用文档在加载状态Loading标签下

附:其余进度条源码

结尾

这个加载进度条的关键点在于站在用户的角度去考虑真实的加载过程是怎样的,这样仿真效果也最好哈哈。更多有趣的组件尽在SluckyUI中,欢迎多多交流,期待你的加入。其中涉及的组件已更新在npm,npm i slucky安装最新版本便可使用。

从零开始系列传送门

相关文章
相关标签/搜索