什麼?你還在使用這種懶加載方式?

導讀


相信不少小夥伴在工做中都會遇到圖片請求數量過多,致使出現頁面會出現卡頓的狀況,在咱們前端開發工做中,頁面的渲染速度是十分重要的。
談到這,咱們都知道其中最大的一個問題就是圖片加載速度會拖累整個頁面體驗。不少頁面,內容很豐富,頁面很長,圖片較多,好比說各類商城頁面。這些頁面圖片數量多,並且比較大,少說百來K,多則上兆。有的時候沒有必要一次性加載完。不然常會出現加載半張圖片或是殘缺,網速很差的有時候還會出現圖片加載不出來等問題。
那麼咱們可使用現有的技術,先顯示可視區域中的圖片,再使剩餘圖片未顯示的圖片和滾動條事件作交互,「滑到你,你再顯示出來」,這也就是咱們常說的懶加載,來咱們看一下關於懶加載的定義。前端

懶加載(Load On Demand)是一種獨特而又強大的數據獲取方法,它可以在用戶滾動頁面的時候自動獲取更多的數據,而新獲得的數據不會影響原有數據的顯示,同時最大程度上減小服務器端的資源耗用。git

關於懶加載的方式有不少種,在這裏只會着重介紹其中兩種,傳統的懶加載方式以及交叉觀察者這兩種方式。github

傳統的懶加載方式


傳統的懶加載方式其實就是經過監聽滾動軸的變化,去請求出如今可視區域的圖片。數組

原理

將頁面中的img標籤src指向一張小圖片或者src爲空,而後定義data-src(這個屬性能夠自定義命名,我採用data-src)屬性指向真實的圖片。
瀏覽器

新建一個HTML文件

<div class="box">
    // 在這裏咱們使用自定義屬性data-src存儲真實的圖片地址
    <img style="margin-top: 600px;" class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e26e2947?w=533&h=300&f=jpeg&s=44672"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e28ba479?w=500&h=463&f=jpeg&s=10435"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5b3c69c?w=579&h=300&f=jpeg&s=23132"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e60d6bc9?w=500&h=394&f=jpeg&s=27013"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5ac147c?w=500&h=313&f=jpeg&s=29734"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d1e5d0a8ef?w=428&h=600&f=jpeg&s=37727"
        alt="">
    <img class="img" src=""
        data-src="https://user-gold-cdn.xitu.io/2019/9/7/16d0a7d2033996bc?w=500&h=325&f=jpeg&s=9951"
        alt="">
</div>

複製代碼

新建一個CSS文件

.box {
    width: 800px;
    height: 400px;
    border: 1px solid;
    overflow: auto;
}

.img {
    width: 100px;
    height: 100px;
    border: 1px solid;
    display: block;
    margin: 40px auto;
}

複製代碼

在這裏咱們基本能夠實現一個這樣的界面bash

實現懶加載

1.首先咱們先去獲取父級元素以及子元素

const box = document.querySelector('.box');
const imgs = document.querySelectorAll('.img');

2.監聽父級滾動軸變化

box.addEventListener('scroll', handleListenScroll);

3.實現監聽函數

function handleListenScroll() {
    //獲取父級滾動軸距離頂部距離
    var scrollTop = box.scrollTop;
    
    //獲取父級高度
    var divHeight = box.clientHeight;

    for (var i = 0; i < imgs.length; i++){
        if (imgs[i].offsetTop < divHeight + scrollTop) {
          imgs[i].src = imgs[i].getAttribute('data-src');
        }
    }
}

這樣一個簡單的懶加載就實現了,咱們看下效果。

複製代碼

優化

若是直接將函數綁定在scroll事件上,當頁面滾動時,函數會被高頻觸發,這很是影響瀏覽器的性能。服務器

所謂節流,就是當持續觸發事件時,保證必定時間段內只調用一次事件處理函數。這裏也許會有小夥伴說了,防抖呢?先說一下防抖的概念吧,當持續觸發事件時,必定時間段內沒有再觸發事件,事件處理函數纔會執行一次,若是設定的時間到來以前,又一次觸發了事件,就從新開始延時。根據咱們的場景,顯然在這裏使用防抖是不太合適的。app

box.addEventListener('scroll', throttle(handleListenScroll, 500));

//節流實現
function throttle(func, delay) {
    var previous = 0;
    return function () {
        let now = Date.now();
        let context = this;
        let args = arguments;
        if (now - previous > delay) {
            func.apply(context, args);
            previous = now;
        }
    };
}

複製代碼

小tip 在使用的時候咱們也能夠給每一個圖片一個默認圖片,等圖片出如今可視區域的時候進行一個替換。異步


交叉觀察者


交叉觀察者其實就是利用IntersectionObserver接口 (從屬於Intersection Observer API) 提供了一種異步觀察目標元素與其祖先元素或頂級文檔視窗(viewport)交叉狀態的方法。祖先元素與視窗(viewport)被稱爲根(root)。函數

用通俗的話來說就是判斷目標元素有沒有和父級元素產生交叉行爲,一張圖說明一切,畫的醜,請見諒~~

兼容性

呃呃呃, IE幾乎全軍覆沒,不過,有官方提供過的polyfill,啥都不用怕,點這裏

屬性和方法

屬性 介紹
root 所監聽對象的具體祖先元素(element)。若是未傳入值或值爲null,則默認使用頂級文檔的視窗。
rootMargin 計算交叉時添加到根(root)邊界盒bounding box的矩形偏移量, 能夠有效的縮小或擴大根的斷定範圍從而知足計算須要
thresholds 一個包含閾值的列表, 按升序排列, 列表中的每一個閾值都是監聽對象的交叉區域與邊界區域的比率。

方法 介紹
disconnect() 使IntersectionObserver對象中止監聽工做
observe() 使IntersectionObserver開始監聽一個目標元素。
takeRecords() 返回全部觀察目標的IntersectionObserverEntry對象數組。
unobserve() 使IntersectionObserver中止監聽特定目標元素。

使用

1.新建一個IntersectionObserver對象。

const observer = new IntersectionObserver(entries => {
    // 發生交叉目標元素集合
    console.log(entries);
}, option);
    
在這裏callback會返回給咱們當前已監聽而且發生了交叉的目標集合,咱們看一下具體信息。
    
複製代碼

屬性 介紹
boundingClientRect 空間信息
target 目標元素
isIntersecting 是否發生交叉

2.監聽目標元素

const box = document.querySelector('.box');
const imgs = document.querySelectorAll('.img');

const observer = new IntersectionObserver(entries => {
    // 發生交叉目標元素集合
    entries.forEach(item => {
        // 判斷是否發生交叉
        if (item.isIntersecting) {
            // 替換目標元素Url
            item.target.src = item.target.dataset.src;
            // 取消監聽此目標元素
            observer.unobserve(item.target);
        }
    });
}, {
    root: box, // 父級元素
    rootMargin: '20px 0px 100px 0px' // 設置偏移 咱們能夠設置在目標元素距離底部100px的時候發送請求
});

imgs.forEach(item => {
    // 監聽目標元素
    observer.observe(item);
});

複製代碼

實現

以上就是使用IntersectionObserver實現懶加載的過程,是否是很簡單呢,在這裏咱們再也不須要去監聽滾動條的變化,只須要根據返回給咱們的元素集合就能夠實現。還要記住必須是子元素跟父元素髮生交叉,是不能夠去檢查兩個非父子關係的交叉的狀況哦~~


綜上 就是我對於懶加載一點小看法,也但願將來咱們的頁面更加流暢,so,先從懶加載開始吧~~。其實懶加載只是經過IntersectionObserver實現的一點小功能,IntersectionObserver還能夠幫咱們實現吸頂觸底這些功能,感興趣的小夥伴能夠去試試哦。最後,文中若有錯誤,歡迎在評論區指正,若是這篇文章幫助到了你,歡迎點贊👍和關注,😀。

推薦閱讀


參考


相關文章
相關標籤/搜索