懶載入問題描述
- 網站上有大量圖片,若一次性直接請求所有的圖片資源,很顯然時間等待過長,浪費資源。
- 所以我們就需要需要給圖片做一個懶載入,即:等看到圖片,或者快看到圖片時,才去載入
- 就像移動端下拉載入一樣
- 也有種資料分頁的感覺
懶載入問題解決思路
- 第一步,初始時,先給圖片一個
loading.gif
作為img
的src
的值,使其顯示載入中,如:img.src = loading.gif
- 第二步,判斷元素是否進入視口,是否(即將)能看到,再將
img
的src
的值,替換為真正的需求請求地址的值 - 第三步,當
img
有src
的值的時候,就會立刻發請求,請求伺服器的資源,請求成功了,就成功了,就達到我們想要的效果 - 第四步,兜錯,若圖片載入請求失敗的話,再將
img
的src
替換成一張載入失敗錯誤的圖片src
即可
這裡有兩個重點,大家需要注意:
問題一:如何判斷元素是否進入可視區域?
問題二:如何判斷圖片載入成功或失敗了?
這兩個問題的答案後文會提到,大家繼續往下閱讀
圖片懶載入效果
最終實現的就是這樣的效果
也可以去筆者的個人網站上,看效果圖:http://ashuai.work:8888/#/img...
解決方案
- 或者使用現有的外掛
- 或者自己寫一個
方案一 外掛就是好!vue-lazyload
推薦使用vue-lazyload
外掛各方面都很最佳化,官方地址:https://www.npmjs.com/package...
使用步驟,這裡筆者就不贅述了,上述的效果圖,也是透過這個vue-lazyload
外掛實現的,對應程式碼,在筆者的GitHub
倉庫中:https://github.com/shuirongsh...
方案二 自己手寫一個自定義指令v-lazyload
寫一個自定義指令,便於邏輯複用
如何判斷元素是否進入視口了?
麻煩一些的方案:監聽擁有捲軸的scroll事件,去計算元素距離擁有捲軸的位置,這裡筆者總結了一個公式:
滾動距離出現 = .target距頂部高度 - .scrollBox距頂部高度 - .scrollBox自身高度
- 或
邊界值 = 目標元素距頂部高度 - 滾動盒子容器距頂部高度 - 滾動盒子容器自身高度
相關程式碼案例,請看筆者的這篇文章:https://segmentfault.com/a/11...
使用IntersectionObserver類建構函式,去判斷元素是否進入視口
IntersectionObserver
是一個非常強大的api,可以觀測很多東西的變化,very good
,在瀏覽器版本不斷更新迭代的現在,其相容性已經非常不錯了,大家可以放心使用。
關於IntersectionObserver的語法,筆者不贅述了,我們們直接上自定義指令程式碼
自定義指令程式碼
// let loadimage = "http://ashuai.work:10000/imgGifSrc/loading.gif" // 伺服器載入中圖片
// let errorimage = "http://ashuai.work:10000/imgGifSrc/error.gif" // 伺服器載入中圖片
let loadimage = require('../../assets/imgLazyload/loading.gif') // 本地載入中圖片
let errorimage = require('../../assets/imgLazyload/error.gif') // 本地載入失敗圖片
export default {
inserted(el, binding, vnode) {
// 1. 先讓圖片顯示載入中...
el.src = loadimage.default
// 2. 例項化一個:觀察檢測者
const observer = new IntersectionObserver((entries) => {
// 4. 在觀察監測者的對應執行函式中獲取到isIntersecting屬性(是否交叉)
let isIntersecting = entries[0].isIntersecting
// 5. 如果交叉了,就讓其去載入對應src的真正的地址
if (isIntersecting) {
el.src = binding.value
// 6. 載入成功就不用管它
el.onload = (res) => console.log('載入成功', res);
// 7. 載入失敗了就去做一個錯誤圖片的佔位
el.onerror = (err) => {
console.log('載入失敗', err);
el.src = errorimage.default
}
// 8. 無論載入成功或失敗,都停止觀察任務了
observer.unobserve(el)
}
})
// 3. 讓這個觀察檢測者去觀察對應img標籤圖片
observer.observe(el)
},
}
使用程式碼
使用的話,很簡單,直接:
<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/doupo.png'" />
<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/douluo.png'" />
<img class='imgLazy' v-lazyload="'http://ashuai.work:10000/imgSrc/tunshi.png'" />
注意使用自定義指令別忘了要註冊哦
最後,煩請各位道友去筆者的GitHub倉庫看看,如果覺得對您有一點點幫助的話,不妨不吝star?
自定義指令的完整程式碼也在筆者的GitHub倉庫中哦