最近在作移動端的營銷頁面時,遇到了頁面有大量圖片的狀況,因而很天然的想到了要使用圖片lazyload,PC端用着jQuery,也有現成的插件。
可是在移動端,基本不用jQuery,因而就試着本身去造一下輪子。
實現lazyload並不難,我很快就想到如下幾個步驟:css
在這簡單的幾個步驟中,也有幾個細節要點須要注意:html
其中上面要點2比較坑。瀏覽器
垂直Y方向直接監聽window的scroll便可,但水平X方向的多半是頁面內某個元素設定了必定區域並overflow:auto; 恰恰頁面內元素的scroll事件是不會冒泡的,事件的bubbles爲false,即不可冒泡函數
默認的頁面滾動事件是可冒泡的,由document開始觸發,冒泡到window,事件的bubbles爲true,便可冒泡,最坑的是獲取和設置scrollTop等值時,倒是使用 body 或 html 元素,水平有限,不理解爲何會是割裂開的。性能
對於這個問題,暫時沒想到好的解決方案,暫時用寫2次的方法解決,如lazyload(window),再lazyload('#container')監聽各自的事件測試
而判斷圖片是否出現時,剛開始我是使用elem.offsetTop對比scrollTop,後來發現offsetTop是相對最近的定位元素的,很容易就坑了。spa
一番尋覓後才發現 elem.getBoundingClientRect(),一番查資料後總結了這個方法的一些要點prototype
elem.getBoundingClientRect() 獲取 元素相對於瀏覽器窗口的距離,會受到滾動的影響,實時獲取,translate,scale等transform屬性也會影響結果
getBoundingClientRect是DOM元素到瀏覽器可視範圍的距離(不包含文檔卷起的部分)。
該函數返回一個Object對象,該對象有6個屬性:top,lef,right,bottom,width,height;
這裏的top、left和css中的理解很類似,width、height是元素自身的寬高,
可是right,bottom和css中的理解有點不同。right是指元素右邊界距窗口最左邊的距離,bottom是指元素下邊界距窗口最上面的距離。插件
踩完一些坑後,總算仿照PC端的jQuery插件完成了輪子,代碼以下code
function lazyload(options){ var settings = { selector : 'img.lazy', container : window, threshold : 0, failurelimit : 0, dataAttribute : "data-original", }; if(typeof options == 'object'){ for(var key in options){ settings[key] = options[key] || settings[key]; } } var tId = null; var imgsArr = Array.prototype.slice.call(document.querySelectorAll(settings.selector)); function inViewport(elem, threshold){ var o = elem.getBoundingClientRect(); var pageWidth = document.documentElement.clientWidth; var pageHeight = document.documentElement.clientHeight; threshold = threshold || pageHeight/5; return o.left < pageWidth + threshold && o.top < pageHeight + threshold } function loadImg(){ clearTimeout(tId); tId = setTimeout(function(){ var scrollTop = document.documentElement.scrollTop || document.body.scrollTop; var src = ''; var item = null; var counter = 0; if(imgsArr.length > 0){ for (var i = 0; i < imgsArr.length; i++) { item = imgsArr[i]; if( inViewport(item) ){ src = item.getAttribute(settings.dataAttribute); item.setAttribute('src', src); imgsArr.splice(i,1); i--; counter = 0; }else if( ++counter > settings.failurelimit ){ break; } }; }else { settings.container.removeEventListener('scroll',loadImg); } }, 100); } loadImg(); settings.container.addEventListener('scroll',loadImg); }
使用時和jQuery的lazyload插件相似,只是沒有了$,直接使用函數lazyload();默認配置以下
lazyload({ selector : 'img.lazy', // 選擇器 container : window, // 容器 threshold : 0, // 預留間距,即圖片距離屏幕還有必定距離就預先加載 failurelimit : 0, // failurelimit,值爲數字.lazyload默認在找到第一張不在可見區域裏的圖片時則再也不繼續加載,但當HTML容器混亂的時候可能出現可見區域內圖片並沒加載出來的狀況,failurelimit意在加載N張可見區域外的圖片,以免出現這個問題. dataAttribute : "data-original", // 存放真實URL的屬性 });
以上實現尚未測試兼容,純屬交流,歡迎指正