經(jīng)典的jQuery實(shí)現(xiàn)圖片懶加載的一種方法

對(duì)于一個(gè)有多個(gè)圖片的網(wǎng)站來說,訪問的時(shí)候不應(yīng)該直接加載所有圖片,而是應(yīng)該只講瀏覽器窗口內(nèi)的圖片進(jìn)行加載。當(dāng)滾動(dòng)的時(shí)候,在加載更多的圖片。叫做圖片的懶加載。

我們可以通過給img自定義一個(gè)新屬性,來存儲(chǔ)圖片真實(shí)的src地址,當(dāng)需要加載的時(shí)候,再將這個(gè)真實(shí)的地址賦給src,進(jìn)行圖片加載。

整體思路:

所以大體的思路為:

  • 設(shè)置個(gè)data-src(自定義一個(gè)屬性)來存放真實(shí)地址
  • 當(dāng)滾動(dòng)頁面時(shí),檢查所有的img標(biāo)簽,看是否出現(xiàn)在視野中,如果已經(jīng)出現(xiàn)在了視野中,那繼續(xù)再進(jìn)行判斷,看其是否已經(jīng)被加載過了,如果還沒有被加載過,那就進(jìn)行加載。

想到這一步,整體的大概思路可以寫為:

    $(window).on('scroll',function () {//當(dāng)頁面滾動(dòng)的時(shí)候綁定事件
        $('.container img').each(function () {//遍歷所有的img標(biāo)簽
            if (checkShow($(this)) && !isLoaded($(this)) ){
                // 需要寫一個(gè)checkShow函數(shù)來判斷當(dāng)前img是否已經(jīng)出現(xiàn)在了視野中
                //還需要寫一個(gè)isLoaded函數(shù)判斷當(dāng)前img是否已經(jīng)被加載過了
                loadImg($(this));//符合上述條件之后,再寫一個(gè)加載函數(shù)加載當(dāng)前img
            }
        })
    })
    function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象

    }
    function isLoaded ($img) {

    }
    function loadImg ($img) {
        
    }

判斷目標(biāo)標(biāo)簽是否出現(xiàn)在視野中:

此時(shí),判斷目標(biāo)標(biāo)簽是否已經(jīng)出現(xiàn)在視野中的思路為:
分析標(biāo)簽出現(xiàn)在頁面中的兩個(gè)臨界狀態(tài):

  • 當(dāng)頁面向上滾動(dòng),一直滾到首先出現(xiàn)在頁面的下邊緣的時(shí)候,此時(shí)有頁面向上滾動(dòng)的距離,加上瀏覽器自身的高度就等于目標(biāo)標(biāo)簽本身在頁面中距離頁面頂部的距離。
  • 頁面接著向上滾,當(dāng)頁面出現(xiàn)在了瀏覽器的上邊沿的時(shí)候,此時(shí)頁面向上滾的高度,就等于目標(biāo)標(biāo)簽本身在頁面中距離頁面頂部的距離
    那么可以checkShow函數(shù)可以寫為:
    .offset()方法允許我們檢索一個(gè)元素 (包含其 border 邊框,不包括 margin) 相對(duì)于文檔(document)的當(dāng)前位置。.offset()返回一個(gè)包含top 和 left屬性的對(duì)象 。表示相對(duì)于頂部或者左邊的坐標(biāo)。
    function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象
        var scrollTop = $(window).scrollTop();  //即頁面向上滾動(dòng)的距離
        var windowHeight = $(window).height(); // 瀏覽器自身的高度
        var offsetTop = $img.offset().top;  //目標(biāo)標(biāo)簽img相對(duì)于document頂部的位置

        if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2個(gè)臨界狀態(tài)之間的就為出現(xiàn)在視野中的
            return true;
        }
        return false;
    }

判斷目標(biāo)標(biāo)簽是否已經(jīng)被加載過:

    function isLoaded ($img) {
        return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已經(jīng)加載過了
    }

加載目標(biāo)標(biāo)簽

    function loadImg ($img) {
        $img.attr('src',$img.attr('data-src')); // 加載就是把自定義屬性中存放的真實(shí)的src地址賦給src屬性
    }

優(yōu)化代碼

那么此時(shí)的代碼就能實(shí)現(xiàn)大體功能了,此時(shí)完整代碼為:

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>圖片懶加載-簡(jiǎn)單</title>
    <script src="../jquery-3.2.1.min.js"></script>
    <style>
        ul,li{
            list-style:none;
        }
        .container{
            width: 600px;
            margin: 0 auto;
        }
        .container li{
            float: left;
            margin: 10px 10px;
        }
        .container li img{
            width: 240px;
            height: 180px;
        }
        p{
            float: left;
        }
    </style>
</head>
<body>
<ul class="container">
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/1.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/2.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/3.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/4.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/5.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/6.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/7.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/8.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/9.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/10.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/11.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/12.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/13.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/14.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/15.jpg" /></a></li>
    <li><a href="#"><img src="" data-src="http://cdn.jirengu.com/book.jirengu.com/img/16.jpg" /></a></li>
</ul>

<script>
    $(window).on('scroll',function () {//當(dāng)頁面滾動(dòng)的時(shí)候綁定事件
        $('.container img').each(function () {//遍歷所有的img標(biāo)簽
            if (checkShow($(this)) && !isLoaded($(this)) ){
                // 需要寫一個(gè)checkShow函數(shù)來判斷當(dāng)前img是否已經(jīng)出現(xiàn)在了視野中
                //還需要寫一個(gè)isLoaded函數(shù)判斷當(dāng)前img是否已經(jīng)被加載過了
                loadImg($(this));//符合上述條件之后,再寫一個(gè)加載函數(shù)加載當(dāng)前img
            }
        })
    })
    function checkShow($img) { // 傳入一個(gè)img的jq對(duì)象
        var scrollTop = $(window).scrollTop();  //即頁面向上滾動(dòng)的距離
        var windowHeight = $(window).height(); // 瀏覽器自身的高度
        var offsetTop = $img.offset().top;  //目標(biāo)標(biāo)簽img相對(duì)于document頂部的位置

        if (offsetTop < (scrollTop + windowHeight) && offsetTop > scrollTop) { //在2個(gè)臨界狀態(tài)之間的就為出現(xiàn)在視野中的
            return true;
        }
        return false;
    }
    function isLoaded ($img) {
        return $img.attr('data-src') === $img.attr('src'); //如果data-src和src相等那么就是已經(jīng)加載過了
    }
    function loadImg ($img) {
        $img.attr('src',$img.attr('data-src')); // 加載就是把自定義屬性中存放的真實(shí)的src地址賦給src屬性
    }
</script>
</body>
</html>

首先有個(gè)明顯的問題,目前頁面上,第一次進(jìn)來的時(shí)候如果不滾動(dòng)滾輪的話什么都看不到,想修復(fù)這個(gè)問題,可以先進(jìn)行一次頁面檢查,調(diào)用checkShow(),然后頁面上在視野中的標(biāo)簽就會(huì)被加載,然后再進(jìn)行監(jiān)聽window的scroll事件。

    // 先進(jìn)行一次檢查
    $('.container img').each(function () {
        if (checkShow($(this)) && !isLoaded($(this)) ){
            loadImg($(this));
        }
    })
    $(window).on('scroll',function () {
        $('.container img').each(function () {
            if (checkShow($(this)) && !isLoaded($(this)) ){
                loadImg($(this));
            }
        })
    })

但是此時(shí)代碼有重復(fù)的,進(jìn)行優(yōu)化。將重復(fù)的代碼塊寫成一個(gè)新的函數(shù)。進(jìn)行替換。

    // 先進(jìn)行一次檢查
    lazyRender();
    $(window).on('scroll',function () {
        lazyRender();
    })
    function lazyRender () {
        $('.container img').each(function () {
            if (checkShow($(this)) && !isLoaded($(this)) ){
                loadImg($(this));
            }
        })
    }

代碼優(yōu)化已經(jīng)很好了,對(duì)于性能的優(yōu)化:
$(window).on('scroll',function () {}這個(gè)事件鼠標(biāo)滾動(dòng)的時(shí)候觸發(fā)次數(shù)非常多。對(duì)性能影響大,優(yōu)化思路是當(dāng)鼠標(biāo)滾輪停止?jié)L動(dòng)的時(shí)候,再去判定是否存在在視野中,而不是滾動(dòng)過程中一直觸發(fā)。


    // 先進(jìn)行一次檢查
    lazyRender();
    //為了不在滾輪滾動(dòng)過程中就一直判定,設(shè)置個(gè)setTimeout,等停止?jié)L動(dòng)后再去判定是否出現(xiàn)在視野中。
    var clock; //這里的clock為timeID,
    $(window).on('scroll',function () {
//        lazyRender();
        if (clock) { // 如果在300毫秒內(nèi)進(jìn)行scroll的話,都會(huì)被clearTimeout掉,setTimeout不會(huì)執(zhí)行。
                    //如果有300毫秒外的操作,會(huì)得到一個(gè)新的timeID即clock,會(huì)執(zhí)行一次setTimeout,然后保存這次setTimeout的ID,
                      //對(duì)于300毫秒內(nèi)的scroll事件,不會(huì)生成新的timeID值,所以會(huì)一直被clearTimeout掉,不會(huì)執(zhí)行setTimeout.
            clearTimeout(clock);
        }
        clock = setTimeout(function () {
            console.log('運(yùn)行了一次');
            lazyRender();
        },300)
    })

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,045評(píng)論 25 709
  • 發(fā)現(xiàn) 關(guān)注 消息 iOS 第三方庫、插件、知名博客總結(jié) 作者大灰狼的小綿羊哥哥關(guān)注 2017.06.26 09:4...
    肇東周閱讀 15,327評(píng)論 4 61
  • 問答題47 /72 常見瀏覽器兼容性問題與解決方案? 參考答案 (1)瀏覽器兼容問題一:不同瀏覽器的標(biāo)簽?zāi)J(rèn)的外補(bǔ)...
    _Yfling閱讀 14,153評(píng)論 1 92
  • 小柒說,活著是為了想念某些東西。想念多年前自己心儀的那個(gè)溫柔的男同學(xué),想念一群人整天坐在一起上課的時(shí)光,想念那年榕...
    王玦閱讀 803評(píng)論 1 4
  • 明日就兒童節(jié)了,邀朋友帶上兒子來家里玩。兩個(gè)小孩一起,各種讓媽媽們滿意:不用陪他們玩無聊的手推車,不用對(duì)他們重復(fù)白...
    陶珍閱讀 424評(píng)論 0 0

友情鏈接更多精彩內(nèi)容