最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

javascript實現(xiàn)一個網(wǎng)頁加載進度loading

 更新時間:2017年01月04日 12:39:14   作者:likar  
本篇文章主要介紹了javascript實現(xiàn)一個頁面加載進度loading的具體步驟以及示例代碼,具有一定的參考價值,下面跟著小編一起來看下吧

loading隨處可見,比如一個app經(jīng)常會有下拉刷新,上拉加載的功能,在刷新和加載的過程中為了讓用戶感知到 load 的過程,我們會使用一些過渡動畫來表達。最常見的比如“轉(zhuǎn)圈圈”,“省略號”等等。

網(wǎng)頁loading有很多用處,比如頁面的加載進度,數(shù)據(jù)的加載過程等等,數(shù)據(jù)的加載loading很好做,只需要在加載數(shù)據(jù)之前(before ajax)顯示loading效果,在數(shù)據(jù)返回之后(ajax completed)結(jié)束loading效果,就可以了。

但是頁面的加載進度,需要一點技巧。

頁面加載進度一直以來都是一個常見而又晦澀的需求,常見是因為它在某些“重”網(wǎng)頁(特別是網(wǎng)頁游戲)的應用特別重要;晦澀是因為web的特性,各種零散資源決定它很難是“真實”的進度,只能是一種“假”的進度,至少在邏輯代碼加載完成之前,我們都不能統(tǒng)計到進度,而邏輯代碼自身的進度也無法統(tǒng)計。另外,我們不可能監(jiān)控到所有資源的加載情況。

所以頁面的加載進度都是“假”的,它存在的目的是為了提高用戶體驗,使用戶不至于在打開頁面之后長時間面對一片空白,導致用戶流失。

既然是“假”的,我們就要做到“仿真”才有用。仿真是有意義的,事實上用戶并不在乎某一刻你是不是真的加載到了百分之幾,他只關心你還要load多久。所以接下來我們就來實現(xiàn)一個頁面加載進度loading。

首先準備一段loading的html:

<!DOCTYPE html>
<html>
<head>
 <title>動手實現(xiàn)一個網(wǎng)頁加載進度loading</title>
</head>
<body>
 <div class="loading" id="loading">
 <div class="progress" id="progress">0%</div>
 </div>
</body>
</html>

來點樣式裝扮一下:

.loading {
 display: table;
 position: fixed;
 top: 0;
 left: 0;
 width: 100%;
 height: 100%;
 background-color: #fff;
 z-index: 5;
}
.loading .progress {
 display: table-cell;
 vertical-align: middle;
 text-align: center;
}

我們先假設這個loading只需要在頁面加載完成之后隱藏,中間不需要顯示進度。那么很簡單,我們第一時間想到的就是window.onload:

(以下內(nèi)容為了方便演示,默認使用jQuery,語法有es6的箭頭函數(shù))

var $loading = $('#loading')
var $progress = $('#progress')
window.onload = () => {
 $loading.hide()
}

ok,這樣基本的loading流程就有了,我們增加一個進度的效果,每隔100ms就自增1,一直到100%為止,而另一方面window loaded的時候,我們把loading給隱藏。

我們來補充一下進度:

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0 // 初始化進度
var timer = window.setInterval(() => { // 設置定時器
 if (prg >= 100) { // 到達終點,關閉定時器
 window.clearInterval(timer)
 prg = 100
 } else { // 未到終點,進度自增
 prg++
 }
 $progress.html(prg + '%')
 console.log(prg)
}, 100)
window.onload = () => {
 $loading.hide()
}

效果不錯,但是有個問題,萬一window loaded太慢了,導致進度顯示load到100%了,loading還沒有隱藏,那就打臉了。所以,我們需要讓loading在window loaded的時候才到達終點,在這之前,loading可以保持一個等待的狀態(tài),比如在80%的時候,先停一停,然后在loaded的時候快速將進度推至100%。這個做法是目前絕大部份進度條的做法。

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = window.setInterval(() => {
 if (prg >= 80) { // 到達第一階段80%,關閉定時器,保持等待
 window.clearInterval(timer)
 prg = 100
 } else {
 prg++
 }
 $progress.html(prg + '%')
 console.log(prg)
}, 100)
window.onload = () => {
 window.clearInterval(timer)
 window.setInterval(() => {
 if (prg >= 100) { // 到達終點,關閉定時器
 window.clearInterval(timer)
 prg = 100
 $loading.hide()
 } else {
 prg++
 }
 $progress.html(prg + '%')
 console.log(prg)
 }, 10) // 時間間隔縮短
}

ok,這差不多就是我們想要的功能了,我們來提煉一下代碼,把重復的代碼給封裝一下:

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = 0
progress(80, 100)
window.onload = () => {
 progress(100, 10, () => {
 $loading.hide()
 })
}
function progress (dist, delay, callback) {
 window.clearInterval(timer)
 timer = window.setInterval(() => {
 if (prg >= dist) {
 window.clearInterval(timer)
 prg = dist
 callback && callback()
 } else {
 prg++
 }
 $progress.html(prg + '%')
 console.log(prg)
 }, delay)
}

我們得到了一個progress函數(shù),這個函數(shù)就是我們主要的功能模塊,通過傳入一個目標值、一個時間間隔,就可以模擬進度的演化過程。

目前來看,這個進度還是有些問題的:

  1.0、進度太平均,相同的時間間隔,相同的增量,不符合網(wǎng)絡環(huán)境的特點;

  2.0、window.onload太快,我們還來不及看清100%,loading就已經(jīng)不見了;

  3.0、每次第一階段都是在80%就暫停了,露餡兒了;

第一個點,我們要讓時間間隔隨機,增量也隨機;第二個點很簡單,我們延遲一下就好了;第三點也需要我們隨機產(chǎn)生一個初始值。

增量隨機很好辦,如何讓時間間隔隨機?setInterval是無法動態(tài)設置delay的,那么我們就要把它改造一下,使用setTimeout來實現(xiàn)。(setInterval跟setTimeout的用法和區(qū)別就不細說了吧?)

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = 0
progress([80, 90], [1, 3], 100) // 使用數(shù)組來表示隨機數(shù)的區(qū)間
window.onload = () => {
 progress(100, [1, 5], 10, () => {
 window.setTimeout(() => { // 延遲了一秒再隱藏loading
 $loading.hide()
 }, 1000)
 })
}
function progress (dist, speed, delay, callback) {
 var _dist = random(dist)
 var _delay = random(delay)
 var _speed = random(speed)
 window.clearTimeout(timer)
 timer = window.setTimeout(() => {
 if (prg + _speed >= _dist) {
 window.clearTimeout(timer)
 prg = _dist
 callback && callback()
 } else {
 prg += _speed
 progress (_dist, speed, delay, callback)
 }
 $progress.html(parseInt(prg) + '%') // 留意,由于已經(jīng)不是自增1,所以這里要取整
 console.log(prg)
 }, _delay)
}
function random (n) {
 if (typeof n === 'object') {
 var times = n[1] - n[0]
 var offset = n[0]
 return Math.random() * times + offset
 } else {
 return n
 }
}

至此,我們差不多完成了需求。

but,還有一個比較隱蔽的問題,我們現(xiàn)在使用window.onload,發(fā)現(xiàn)從進入頁面,到window.onload這中間相隔時間十分短,我們基本是感受不到第一階段進度(80%)的,這是沒有問題的——我們在意的是,如果頁面的加載資源數(shù)量很多,體積很大的時候,從進入頁面,到window.onload就不是這么快速了,這中間可能會很漫長(5~20秒不等),但事實上,我們只需要為 首屏資源 的加載爭取時間就可以了,不需要等待所有資源就緒,而且更快地呈現(xiàn)頁面也是提高用戶體驗的關鍵。

我們應該考慮頁面loading停留過久的情況,我們需要為loading設置一個超時時間,超過這個時間,假設window.onload還沒有完成,我們也要把進度推到100%,把loading結(jié)束掉。

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = 0
progress([80, 90], [1, 3], 100) // 使用數(shù)組來表示隨機數(shù)的區(qū)間
window.onload = () => {
 progress(100, [1, 5], 10, () => {
 window.setTimeout(() => { // 延遲了一秒再隱藏loading
 $loading.hide()
 }, 1000)
 })
}
window.setTimeout(() => { // 設置5秒的超時時間
 progress(100, [1, 5], 10, () => {
 window.setTimeout(() => { // 延遲了一秒再隱藏loading
 $loading.hide()
 }, 1000)
 })
}, 5000)
function progress (dist, speed, delay, callback) {
 var _dist = random(dist)
 var _delay = random(delay)
 var _speed = random(speed)
 window.clearTimeout(timer)
 timer = window.setTimeout(() => {
 if (prg + _speed >= _dist) {
 window.clearTimeout(timer)
 prg = _dist
 callback && callback()
 } else {
 prg += _speed
 progress (_dist, speed, delay, callback)
 }
 $progress.html(parseInt(prg) + '%') // 留意,由于已經(jīng)不是自增1,所以這里要取整
 console.log(prg)
 }, _delay)
}
function random (n) {
 if (typeof n === 'object') {
 var times = n[1] - n[0]
 var offset = n[0]
 return Math.random() * times + offset
 } else {
 return n
 }
}

我們直接設置了一個定時器,5s的時間來作為超時時間。這樣做是可以的。

but,還是有問題,這個定時器是在js加載完畢之后才開始生效的,也就是說,我們忽略了js加載完畢之前的時間,這誤差可大可小,我們設置的5s,實際用戶可能等待了8s,這是有問題的。我們做用戶體驗,需要從實際情況去考慮,所以這個開始時間還需要再提前一些,我們在head里來記錄這個開始時間,然后在js當中去做對比,如果時間差大于超時時間,那我們就可以直接執(zhí)行最后的完成步驟,如果小于超時時間,則等待 剩余的時間 過后,再完成進度。

先在head里埋點,記錄用戶進入頁面的時間loadingStartTime:

<!DOCTYPE html>
<html>
<head>
 <title>動手實現(xiàn)一個網(wǎng)頁加載進度loading</title>
 <script>
 window.loadingStartTime = new Date()
 </script>
 <script src="index.js"></script>
</head>
<body>
 <div class="loading" id="loading">
 <div class="progress" id="progress">0%</div>
 </div>
</body>
</html>

然后,我們對比 當前的時間 ,看是否超時:(為了方便復用代碼,我把完成的部分封裝成函數(shù)complete)

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = 0
var now = new Date() // 記錄當前時間
var timeout = 5000 // 超時時間
progress([80, 90], [1, 3], 100)
window.onload = () => {
 complete()
}
if (now - loadingStartTime > timeout) { // 超時
 complete()
} else {
 window.setTimeout(() => { // 未超時,則等待剩余時間
 complete()
 }, timeout - (now - loadingStartTime))
}
function complete () { // 封裝完成進度功能
 progress(100, [1, 5], 10, () => {
 window.setTimeout(() => {
 $loading.hide()
 }, 1000)
 })
}
function progress (dist, speed, delay, callback) {
 var _dist = random(dist)
 var _delay = random(delay)
 var _speed = random(speed)
 window.clearTimeout(timer)
 timer = window.setTimeout(() => {
 if (prg + _speed >= _dist) {
 window.clearTimeout(timer)
 prg = _dist
 callback && callback()
 } else {
 prg += _speed
 progress (_dist, speed, delay, callback)
 }
 $progress.html(parseInt(prg) + '%')
 console.log(prg)
 }, _delay)
}
function random (n) {
 if (typeof n === 'object') {
 var times = n[1] - n[0]
 var offset = n[0]
 return Math.random() * times + offset
 } else {
 return n
 }
}

至此,我們算是完整地實現(xiàn)了這一功能。

然而,事情還沒有結(jié)束,少年你太天真。

如果目的是為了寫一個純粹障眼法的偽loading,那跟其他loading的實現(xiàn)就沒什么區(qū)別了,我們做事講究腳踏實地,能實現(xiàn)的實現(xiàn),不能實現(xiàn)的,為了團隊和諧,我們不得已坑蒙拐騙。那么我們還能更貼近實際情況一點嗎?其實是可以的。

我們來分析一個場景,假設我們想讓我們的loading更加真實一些,那么我們可以選擇性地對頁面上幾個比較大的資源的加載進行跟蹤,然后拆分整個進度條,比如我們頁面有三張大圖a、b、c,那么我們將進度條拆成五段,每加載完一張圖我們就推進一個進度:

隨機初始化[10, 20] ->
圖a推進20%的進度 ->
圖b推進25%的進度 ->
圖c推進30%的進度 ->
完成100%

這三張圖要占20% + 25% + 30% = 75%的進度。

問題是,如果圖片加載完成是按照順序來的,那我們可以很簡單地:10(假設初始進度是10%) -> 30 -> 55 -> 85 -> 100,但事實是,圖片不會按照順序來,誰早到誰晚到是說不準的,所以我們需要更合理的方式去管理這些進度增量,使它們不會互相覆蓋。

  1.0、我們需要一個能夠替我們累計增量的變量next;

  2.0、由于我們的progress都是傳目的進度的,我們需要另外一個函數(shù)add,來傳增量進度。

var $loading = $('#loading')
var $progress = $('#progress')
var prg = 0
var timer = 0
var now = new Date()
var timeout = 5000
var next = prg
add([30, 50], [1, 3], 100) // 第一階段
window.setTimeout(() => { // 模擬圖a加載完
 add(20, [1, 3], 200)
}, 1000)
window.setTimeout(() => { // 模擬圖c加載完
 add(30, [1, 3], 200)
}, 2000)
window.setTimeout(() => { // 模擬圖b加載完
 add(25, [1, 3], 200)
}, 2500)
window.onload = () => {
 complete()
}
if (now - loadingStartTime > timeout) {
 complete()
} else {
 window.setTimeout(() => {
 complete()
 }, timeout - (now - loadingStartTime))
}
function complete () {
 add(100, [1, 5], 10, () => {
 window.setTimeout(() => {
 $loading.hide()
 }, 1000)
 })
}
function add (dist, speed, delay, callback) {
 var _dist = random(dist)
 if (next + _dist > 100) { // 對超出部分裁剪對齊
 next = 100
 } else {
 next += _dist
 }
 progress(next, speed, delay, callback)
}
function progress (dist, speed, delay, callback) {
 var _delay = random(delay)
 var _speed = random(speed)
 window.clearTimeout(timer)
 timer = window.setTimeout(() => {
 if (prg + _speed >= dist) {
 window.clearTimeout(timer)
 prg = dist
 callback && callback()
 } else {
 prg += _speed
 progress (dist, speed, delay, callback)
 }
 $progress.html(parseInt(prg) + '%')
 console.log(prg)
 }, _delay)
}
function random (n) {
 if (typeof n === 'object') {
 var times = n[1] - n[0]
 var offset = n[0]
 return Math.random() * times + offset
 } else {
 return n
 }
}

我們這里為了方便,用setTimeout來模擬圖片的加載,真實應用應該是使用image.onload。

接下來整理一下有點亂的代碼,封裝成一個插件,下載地址為:http://xiazai.jb51.net/201701/yuanma/ez-progress-master_jb51.rar

ez-progress 是一個web(偽)進度插件,使用 ez-progress 實現(xiàn)這個功能非常簡單:

var Progress = require('ez-progress')
var prg = new Progress()
var $loading = $('#loading')
var $progress = $('#progress')
prg.on('progress', function (res) {
 var progress = parseInt(res.progress) // 注意進度取整,不然有可能會出現(xiàn)小數(shù)
 $progress.html(progress + '%')
})
prg.go([60, 70], function (res) {
 prg.complete(null, [0, 5], [0, 50]) // 飛一般地沖向終點
}, [0, 3], [0, 200])
window.onload = function () {
 prg.complete(null, [0, 5], [0, 50]) // 飛一般地沖向終點
}

以上就是本文的全部內(nèi)容,希望本文的內(nèi)容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持腳本之家!

相關文章

  • js 轉(zhuǎn)json格式的字符串為對象或數(shù)組(前后臺)的方法

    js 轉(zhuǎn)json格式的字符串為對象或數(shù)組(前后臺)的方法

    下面小編就為大家?guī)硪黄猨s 轉(zhuǎn)json格式的字符串為對象或數(shù)組(前后臺)的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-11-11
  • 多個js與css文件的合并方法詳細說明

    多個js與css文件的合并方法詳細說明

    在Web項目的開發(fā)中,js,css文件會隨著項目的開發(fā)變得越來越多,越來越大,這就給給性能方面帶來一些問題;解決該問題的一個好的方法就是合并js,css文件需要了解的朋友可以參考下
    2012-12-12
  • 理解javascript封裝

    理解javascript封裝

    這篇文章主要幫助大家理解學習javascript封裝,通過封裝可以強制實施信息隱藏,本文為大家分析了封裝的利弊,感興趣的小伙伴們可以參考一下
    2016-02-02
  • 微信小程序?qū)崿F(xiàn)水平時間軸

    微信小程序?qū)崿F(xiàn)水平時間軸

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)水平時間軸,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-05-05
  • 淺談javascript中l(wèi)odash與lodash-es的區(qū)別

    淺談javascript中l(wèi)odash與lodash-es的區(qū)別

    本文主要介紹了javascript中l(wèi)odash與lodash-es的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-10-10
  • JS常見面試試題總結(jié)【去重、遍歷、閉包、繼承等】

    JS常見面試試題總結(jié)【去重、遍歷、閉包、繼承等】

    這篇文章主要介紹了JS常見面試試題,總結(jié)分析了javascript去重、遍歷、閉包、繼等相關算法與操作技巧,需要的朋友可以參考下
    2019-08-08
  • JSONP跨域模擬百度搜索

    JSONP跨域模擬百度搜索

    這篇文章主要介紹了JSONP跨域模擬百度搜索,JSONP是JSON?with?padding?的簡寫,應用JSON的一種新方法,在后來的Web服務中非常流行,JSONP看起來與JSON差不多,只不過是被包含在函數(shù)中調(diào)用的JSON,對此感興趣的小伙伴可以參考一下下面文章內(nèi)容
    2021-12-12
  • 微信小程序倒計時功能實現(xiàn)代碼

    微信小程序倒計時功能實現(xiàn)代碼

    倒計時功能在項目開發(fā)中經(jīng)常會用到,今天小編給大家介紹下微信小程序倒計時功能實現(xiàn)代碼,需要的朋友參考下吧
    2017-11-11
  • 微信通過頁面(H5)直接打開本地app的解決方法

    微信通過頁面(H5)直接打開本地app的解決方法

    這篇文章主要為大家詳細介紹了微信通過頁面(H5)直接打開本地app的解決方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • JS使用setInterval實現(xiàn)的簡單計時器功能示例

    JS使用setInterval實現(xiàn)的簡單計時器功能示例

    這篇文章主要介紹了JS使用setInterval實現(xiàn)的簡單計時器功能,涉及javascript基于setInterval的定時觸發(fā)與數(shù)值運算相關操作技巧,需要的朋友可以參考下
    2018-04-04

最新評論

北京市| 安丘市| 清远市| 靖远县| 扶余县| 双桥区| 察哈| 利川市| 吴川市| 榆中县| 高清| 手机| 滁州市| 淮滨县| 横山县| 新丰县| 体育| 额尔古纳市| 交口县| 淮北市| 渝中区| 商都县| 闻喜县| 益阳市| 密山市| 沈阳市| 宝山区| 常山县| 嵊泗县| 庐江县| 桐柏县| 龙游县| 崇文区| 波密县| 广南县| 云龙县| 宣恩县| 甘谷县| 曲沃县| 睢宁县| 青川县|