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安裝最新版本便可使用。

從零開始系列傳送門

相關文章
相關標籤/搜索