效能最佳化之圖片懶載入使用vue-lazyload或IntersectionObserver觀察檢測者

水冗水孚發表於2023-02-26

懶載入問題描述

  • 網站上有大量圖片,若一次性直接請求所有的圖片資源,很顯然時間等待過長,浪費資源。
  • 所以我們就需要需要給圖片做一個懶載入,即:等看到圖片,或者快看到圖片時,才去載入
  • 就像移動端下拉載入一樣
  • 也有種資料分頁的感覺

懶載入問題解決思路

  • 第一步,初始時,先給圖片一個loading.gif作為imgsrc的值,使其顯示載入中,如:img.src = loading.gif
  • 第二步,判斷元素是否進入視口,是否(即將)能看到,再將imgsrc的值,替換為真正的需求請求地址的值
  • 第三步,當imgsrc的值的時候,就會立刻發請求,請求伺服器的資源,請求成功了,就成功了,就達到我們想要的效果
  • 第四步,兜錯,若圖片載入請求失敗的話,再將imgsrc替換成一張載入失敗錯誤的圖片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倉庫中哦

相關文章