前端優化之圖片懶加載

http請求

若是你學過計算機網絡你就會知道,咱們請求一個帶有n張圖片的html文件實際上會發送n+1次請求,由於在瀏覽器解析html的時候遇到了src,就會請求src後面的內容。html

設想一下若是咱們的頁面有1000000張圖片,那麼若是等待這些圖片響應成功並加載完成時延是很是大的,用戶體驗很是差。vue

那麼咱們可不可讓圖片按需加載呢?當圖片出如今可視區的時候再加載它而不是一開始就加載徹底部圖片。git

圖片懶加載

template:github

<div @scroll="lazyLoad" ref="lazy">
    <img v-for="(src, index) in imgs" src="##" :dataSrc="src" :key="index">
    <!--more img-->
</div>
複製代碼

改變圖片src

監聽最外層div的滾動事件,觸發滾動時遍歷圖片檢測圖片位置,若在可視區內則顯示瀏覽器

loadImg() {
    var img = this.$refs.lazy.getElementsByClassName("lazyImg"); 
    // 已滾動高度+可視區高度
    var top = this.$refs.lazy.scrollTop + this.$refs.lazy.clientHeight;
    
    for(var i = 0; i < img.length; i++) {
        if(img[i].offsetTop <= top) {  // 在可視區內則顯示圖片
            img[i].src = img[i].getAttribute("datasrc");
        }
    }
},
lazyLoad() { 
    this.loadImg();
}
複製代碼

以上就實現了一個圖片懶加載,本篇文章就到這裏,再見。markdown

橋豆麻袋,忽然發現一個嚴重的問題:滾動過程當中會不斷觸發lazyLoad對圖片作一個遍歷並判斷,那麼就會作無數次for循環,更可怕的是,修改一次src會發送一個請求,在滾動的時候咱們的for循環每次都從頭判斷並修改src請求圖片,那麼請求次數可想而知。網絡

函數防抖

若是在滾動過程當中不斷觸發遍歷並判斷圖片是否在可視區的監聽事件,會耗費很大的性能,這裏採用函數防抖:當用戶中止滾動時統一遍歷判斷圖片位置函數

debounce(fn) {
    // 函數防抖:用戶中止操做以後觸發
    clearTimeout(this.timer);
    this.timer = setTimeout(() => {
        fn();
    }, 1000);
}
複製代碼

咱們能夠將加載圖片的方法放在debounce中oop

lazyLoad() {
    this.debounce(this.loadImg);
}
複製代碼

這樣當用戶滾動頁面時,鬆開手纔會執行loadImg來遍歷判斷圖片位置。性能

又出現了一個問題:若是用戶在滾動時從頁面底部上拉到頂部一直沒有鬆手,那麼在這期間都不會執行loadImg,這意味着頁面的圖片都不會顯示,很是影響用戶體驗

防抖優化

咱們規定,若用戶上拉高度大於500px那麼就自動加載一次可視區內圖片,這裏咱們用oldScrollTop記錄上次上拉高度

lazyLoad() {
    // 若是上拉距離大於500px則自動加載
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop; // 更新oldScrollTop
    } else {  // 若是向下拉但小於500px則防抖加載
        this.debounce(this.loadImg);
    }
}
複製代碼

下拉優化

當用戶下拉的時候咱們並不須要執行lazyLoad,由於咱們以前的圖片已經加載過了,因此能夠修改一下lazyLoad

lazyLoad() {
    // 若是上拉距離大於500px則自動加載
    if(this.$refs.lazy.scrollTop - this.oldScrollTop > 500) {
        this.loadImg();
        this.oldScrollTop = this.$refs.lazy.scrollTop;
    } else if(this.$refs.lazy.scrollTop - this.oldScrollTop < 0) {  // 若是向下拉則不作操做
        return ;
    } else {  // 若是向下拉但小於500px則防抖加載
        this.debounce(this.loadImg);
    }
}
複製代碼

減小遍歷個數

最重要的優化已經作完了,可是還能夠從一些小細節更加優化一下,咱們的loadImg方法中每次都是從0號下標開始遍歷檢查圖片,可是在用戶上拉操做以後一部分圖片已經被加載了,就不須要再次去檢查了。

咱們能夠用一個變量len記錄上一次被加載後的最後一個圖片,而後修改一下loadImg

loadImg() {
    var img = this.getImages(); 
    var top = this.$refs.lazy.scrollTop + window.screen.height;
    
    // 從len開始檢查
    for(var i = this.len; i < img.length; i++) {
        if(img[i].offsetTop <= top) {
            img[i].src = img[i].getAttribute("datasrc");
            this.len = i;  // 更新len
        }
    }
}
複製代碼

結語

一個完整的優化版圖片懶加載就完成了,我將該功能封裝成了一個vue的插件

源碼:vue-plugins

該插件庫會持續更新,歡迎star & fork~

相關文章
相關標籤/搜索