函數節流和圖片懶加載

導讀

這篇文章中主要介紹一下函數節流,而後給了一個圖片懶加載的例子,說圖片懶加載的時候順帶提了下怎麼使用JS獲取頁面的寬高,捲上去的長度等。參考來源主要是《JavaScript高級程序設計》。html

函數節流

瀏覽器的DOM操做比起非DOM交互須要更多的內存和cpu時間,連續過多的DOM操做可能會致使瀏覽器掛起甚至崩潰。好比使用onresize,onscroll這些可能會被連續觸發的事件的時候,若是事件處理程序中進行了過多地DOM操做,可能就會使得瀏覽器崩潰。而爲了繞開這個問題,可能就須要使用到函數節流。
好比:瀏覽器

function resizeDiv(){          //在窗口尺寸改變的時候,調整div的高度
    var div = document.getElementById("myDiv");
    console.log(div.offsetWidth);
    div.style.height = div.offsetWidth + "px";

}
window.onresize = function(){
    resizeDiv();
}

上面的代碼在我簡單的拉伸窗口的時候被連續執行了,若是是更復雜的DOM操做,極可能使得瀏覽器崩潰。其實我想要的只是在我改變完窗口大小後,再調整一次myDiv的高度。閉包

函數節流的指導思想是:某些代碼能夠在沒有間斷的狀況下重複執行。第一次調用函數,建立一個定時器,在指定的時間間隔後執行代碼。當第二次調用該函數的時候,它會清除前一次的定時器並設置另外一個。若是前一個定時器已經執行過了,這個操做沒有意義。然而,若是前一個定時器還沒有執行,其實就是替換爲一個新的定時器,目的是隻有在執行函數的請求中止了一段時間後才執行。app

上代碼:函數

function throttle(method,context){
    clearTimeout(method.tId);            //{1}
    method.tId = setTimeout(function(){
        method.call(context);            //{2}
    },100);
}

throttle方法接收兩個參數:要執行的函數及在哪一個做用域中執行。{1}首先清除以前設置的任何定時器,定時器ID是儲存在函數的tId屬性中的。定時器代碼{2}使用call來確保方法在適當的環境中執行。若是沒有給出第二個參數,那麼就在全局做用域內執行該方法。this

仍是上面的例子,此次window.onresize不直接執行事件處理函數了。設計

window.onresize = function(){
    throttle(resizeDiv);
}

這樣,多數狀況下,用戶察覺不到變化,但可以給瀏覽器節省不少計算。code

關於事件節流函數的寫法,網上還看到另外一種方法,能夠傳入延時時間做爲參數,使用了閉包,可是大同小異。
原文在這裏htm

function throttle(method,delay){
    var timer=null;
    return function(){
        var context=this, args=arguments;
        clearTimeout(timer);
        timer=setTimeout(function(){
            method.apply(context,args);
        },delay);
    }
}

同時,那篇文章的做者提到了一個新需求,我以爲也挺實用,就是在函數節流的基礎上間隔固定時間就執行一次。
上代碼:blog

function throttle(method,delay,duration){
    var timer=null, begin=new Date();       //{1}
    return function(){
        var context=this, args=arguments, current=new Date();
        clearTimeout(timer);
        if(current-begin>=duration){        //{2}
             method.apply(context,args);
             begin=current;
        }else{
            timer=setTimeout(function(){
                method.apply(context,args);
            },delay);
        }
    }
}

在{1}處多設置了一個開始時間,而後在每次調用的時候判斷當前時間是否有超過預設的時間間隔,若是超過了,就當即執行一次事件處理函數,而後再將當前時就按記錄下來,如此往復。

圖片懶加載

在頁面須要加載的圖片不少的狀況下,若是一次將全部的圖片所有加載出來,會耗很長的時間,實際的頁面呈現效果確定不會很理想,因此咱們就等到圖片滾動到視口內後,再去對圖片進行加載。

懶加載思路:將頁面裏全部img屬性src屬性用data-xx代替,當頁面滾動直至此圖片出如今可視區域時,用js取到該圖片的data-xx的值賦給src。

咱們這時候首先遇到一個問題,怎麼去判斷圖片是否是進入了視口呢?因而,JS取各類高度的方法就派上用場了。

網頁可見區域寬: document.body.clientWidth;
網頁可見區域高: document.body.clientHeight;
網頁可見區域寬: document.body.offsetWidth (包括邊線的寬);
網頁可見區域高: document.body.offsetHeight (包括邊線的寬);
網頁正文全文寬: document.body.scrollWidth;
網頁正文全文高: document.body.scrollHeight;
網頁被捲去的高: document.body.scrollTop;
網頁被捲去的左: document.body.scrollLeft;
網頁正文部分上: window.screenTop;
網頁正文部分左: window.screenLeft;
屏幕分辨率的高: window.screen.height;
屏幕分辨率的寬: window.screen.width;
屏幕可用工做區高度: window.screen.availHeight;

除了這些難記的屬性以外,還要考慮各個瀏覽器的兼容問題,就拿網頁被捲上去的高來舉例

IE6/7/8/9/10:
對於沒有doctype聲明的頁面裏可使用 document.body.scrollTop 來獲取 scrollTop高度 ;
對於有doctype聲明的頁面則可使用 document.documentElement.scrollTop ;

Safari:
safari 比較特別,有本身獲取scrollTop的函數 : window.pageYOffse t;

Firefox:
直接用 document.documentElement.scrollTop ;

因此,兼容性的寫法就該是:

var srcollTop = document.documentElement.scrollTop || window.pageYOffset || document.body.scrollTop;

有了這些知識,一個圖片懶加載的代碼就能夠寫了,先假定文檔結構以下:

<body>
    <ul id="mainContent">
        <li><img data-src="./lazyloadimgs/0_1.png" alt="" /></li>
        <li><img data-src="./lazyloadimgs/0_2.png" alt="" /></li>
        <li><img data-src="./lazyloadimgs/0_3.png" alt="" /></li>
        <li><img data-src="./lazyloadimgs/mao.jpg" alt="" /></li>
        <li><img data-src="./lazyloadimgs/0_4.png" alt="" /></li>
        <li><img data-src="./lazyloadimgs/0_5.png" alt="" /></li>
        <li><img data-src="./lazyloadimgs/mao.jpg" alt="" /></li>
        <li><img data-src="./lazyloadimgs/0_6.png" alt="" /></li>
    </ul>
</body>
<style>
    #mainContent li{float:left;margin:15px 32px;border:1px solid #333;padding:4px;}
    #mainContent li img{width:300px;height:350px;}
</style>

接下來就是咱們加載圖片的代碼了,思路就是上面所說的,當圖片進入視口後,從圖片的data-src中取值,而後賦給src屬性,完成圖片的加載。

<script>
function showImg(){
    var content = document.getElementById("mainContent");
    var imgLen = content.children.length;
    var seeHeight = document.documentElement.clientHeight;         //可見區域高度
    var srcollTop = document.documentElement.scrollTop||window.pageYOffset||document.body.scrollTop; //滾動條距離頂部高度
    for(var i = 0;i < imgLen; i++){
        var curImg = content.children[i].children[0];
        if(curImg.offsetTop < seeHeight + srcollTop){
            if(curImg.dataset.src != "undefined"){
                curImg.setAttribute("src",curImg.dataset.src);
            }
        }
    }
}
showImg();
window.onscroll = showImg();
</script>

這裏onscroll被觸發了好屢次,咱們不妨用一下上面提到的函數節流。使用閉包的那種寫法,修改上面代碼中的一處:

window.onscroll = throttle(showImg,200);

這差很少就是一個帶函數節流的圖片懶加載的解決方法了。

相關文章
相關標籤/搜索