帶型帶秀專題之 Lazy Load (三)

博客地址:https://guitong.github.io/blo...javascript

上一節中,咱們分析了 jQuery lazyload 源碼,其中有這麼一段:css

/* 在jQuery命名空間內定義了便捷的方法,判斷圖片是否在容器視口範圍內 */
  $.belowthefold = function (element, settings) {...}
  $.rightoffold = function (element, settings) {...}
  $.abovethetop = function (element, settings) {...}
  $.leftofbegin = function (element, settings) {...}
  $.inviewport = function (element, settings) {...}

說實話,這纔是我最感興趣的內容。那麼實現一個lazyload,應該怎樣判斷圖片與瀏覽器可見區域的相對位置呢,如今以$.belowthefold方法爲例,看一下其實現方式:html

$.belowthefold = function(element, settings) {
        var fold;

        if (settings.container === undefined || settings.container === window) {
            fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop();
        } else {
            fold = $(settings.container).offset().top + $(settings.container).height();
        }

        return fold <= $(element).offset().top - settings.threshold;
    };

首先這段代碼的目的是判斷當前元素(圖片)是否在瀏覽器視口的下方。java

變量fold我理解爲當前文檔已「摺疊」的高度,也就是當前瀏覽器視口的最底部至文檔最頂部的距離。與fold變量值相比較的值是$(element).offset().top - settings.threshold,那麼這個值表明什麼呢?git

seetings.threshold是咱們上節提到過的臨界值,默認爲0,這裏咱們能夠先將其忽略。jQuery對象的offset()方法定義以下:github

Get the current coordinates of the first element in the set of matched elements, relative to the documents.chrome

也就是當前元素相對於文檔的座標。它的top值即爲元素到文檔頂部的距離。瀏覽器

那麼也就不難理解,若是這個值大於等於文檔已「摺疊」的高度值,它的位置就在瀏覽器視口的下方。框架

然而這些jQuery方法也是封裝過的方法,咱們還須要探究它們的實現方式。dom

1、如何獲得瀏覽器視口(便可見區域)的大小

如下內容參考自大紅本 — 《JavaScript高級程序設計》,第三版,第八章

跨瀏覽器肯定一個窗口的大小不是一件簡單的事。IE9+、Firefox、Safari、Opera和Chrome均爲此提供了4個屬性:innerWidthinnerHeightouterWidthouterHeight。在IE9+、Safari和Firefox中,outerWidthouterHeight返回瀏覽器窗口自己的尺寸(不管是最外層的window對象仍是從某個框架訪問)。在Opera中,這兩個屬性的值表示頁面視圖容器(這裏所謂的「頁面視圖容器」指的是Opera中單個標籤頁對應的瀏覽器窗口)的大小。而innerWidthinnerHeight則表示該容器中頁面視圖區的大小(減去邊框寬度)。在Chrome中,outerWIdthouterHeightinnerWidthinnerHeight返回相同的值,即視口(viewport)大小而非瀏覽器窗口大小。

IE8及更早版本沒有提供取得當前瀏覽器窗口尺寸的屬性;不過,它經過DOM提供了頁面可見區域的相關信息。

在IE、Firefox、Safari、Opera和Chrome中,document.documentElement.clientWidthdocument.documentElement.clientHeight中保存了頁面視口的信息。在IE6中,這些屬性必須在標準模式下才有效;若是是混雜模式,就必須經過document.body.clientWidthdocument.body.clientHeight取得相同信息。而對於混在模式下的Chrome,則不管經過document.documentElement仍是document.body中的clientWidthclientHeight屬性,均可以取得取得視口的大小。

(跑題了?? )

雖然最終沒法肯定瀏覽器窗口自己的大小,但卻能夠取得頁面視口的大小,以下所示:

var pageWidth = window.innerWidth,
    pageHeight = window.innerHeight;
if (typeof pageWidth != 'number') {
    if (document.compatMode == 'CSS1Compat') {
          pageWidth = document.documentElement.clientWidth;
          pageHeight = document.documentElement.clientHeight;
    } else {
          pageWidth = document.body.clientWidth;
          pageHeight = document.body.clientHeight;
    }
}

這段代碼很好理解,值得注意的是document.compatMode這個屬性。該值代表當前文檔的渲染模式爲「混雜模式」仍是「標準模式」。當值爲'CSS1Compat'表明標準規範模式;當值爲'BackCompat'表明混雜模式。

2、若是獲得文檔在在垂直/水平方向滾動的距離

這裏以垂直方向爲例。

先來看一個stackoverflow上的回答,翻譯以下:

獲取滾動距離的標準方法爲window.scrollY。Chrome、Firefox、Opera、Safari及IE Edge(或更高版本)均支持此方法。若是您僅須要支持這些瀏覽器,使用這個屬性便可。

IE >= 9 支持一個相似的屬性window.pageYOffset,爲了保證兼容性,在現代瀏覽器中會返回與window.scrollY相同的值,儘管它可能在某些時候被棄用。

使用document.documentElement.scrollTopdocument.body.scrollTop的問題是,它們並非老是都被定義了滾動。例如,Chrome和Safari將滾動定義在<body>元素,而Firefox則定義在了document.documentElement返回的<html>元素上。這不是標準化的,而且在將來版本的瀏覽器中可能會發生變化。然而,若是scrollYpageYOffset不存在,則這是獲取滾動位置的惟一方法。


遂總結以下:

window.scrollY || window.pageYOffset || document.body.scrollTop + (document.documentElement && document.documentElement.scrollTop || 0)

通過測試,這個方法是可行的。不過,正如文中所說,果真在將來版本的瀏覽器中發生了變化。在最新的Chrome、Safari、Firefox中測試發現,Chrome與Firefox表現相同,document.documentElement.scrollTop返回滾動值,而document.body.scrollTop返回0,Safari則與它們相反。

再來看一下MDN上對window.scrollY的解釋

window接口的只讀屬性值scrollY返回文檔當前垂直滾動距離的像素值。這個值在如今瀏覽器中是亞像素精準的,這意味着它不必定是一個整數。您能夠從scrollY屬性獲取文檔水平滾動的像素值。

# 語法

var y = window.scrollY

實際上,返回的值是一個雙精度浮點值,指示文檔當前從原點垂直滾動的像素數,其中正值表示向上滾動。若是文檔在子像素精準的設備上呈現,則返回的值也是子像素精準的,而且可能包含一個小數份量。若是文檔沒有向上或向下滾動,則滾動值是 0 。

若是你須要一個整型值,可使用Math.round()方法

用更技術的話說,scrollY返回當前視口頂邊的Y座標,若是沒有視口,則返回 0 。

# 示例

// make sure and go down to the second page
if (window.scrollY) {
  window.scroll(0, 0); // 重置滾動條位置
}

window.scrollByPages(1);

(這個示例 出如今這裏感受怪怪的)

# 注意事項

使用此屬性來檢查使用相對滾動方法時(如;scrollBy()scrollByLines()scrollByPages())文檔是否還沒有滾動。

pageYOffset屬性是scrollY屬性的別名:

window.pageYOffset == window.scrollY // always true

考慮到跨瀏覽器兼容性,使用window.pageYOffset替代window.scrollY。除此以外,舊版本 IE(< 9)不支持這些屬性,必須經過檢查其餘非標準屬性來解決。徹底兼容的的例子以下:

var supportPageOffset = window.pageXOffset !== undefied;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

var scrollX = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
var scrollY = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.document.scrollTop : document.body.scrollTop;

# 規範

CSS Object Model (CSSOM) View ModuleThe definition of 'window.scrollY' in that specification.

==================== 太平洋分割線=======================

那麼能夠總結一下了。

要得到頁面當前的滾動值,window.scrollY是基於標準的方法。然而考慮到跨瀏覽器兼容性,應該使用window.pageYOffset,該屬性是window.scrollY的別名,被絕大多數現代瀏覽器所支持。對於低版本IE瀏覽器(< 9),能夠判斷渲染模式(標準or混雜)來選擇使用document.documentElement.scrollTop/Leftdocument.body.scrollTop/Left方法。

推薦:

var supportPageOffset = window.pageXOffset !== undefined;
var isCSS1Compat = ((document.compatMode || "") === "CSS1Compat");

var scrollX = supportPageOffset ? window.pageXOffset : isCSS1Compat ? document.documentElement.scrollLeft : document.body.scrollLeft;
var scrollY = supportPageOffset ? window.pageYOffset : isCSS1Compat ? document.documentElement.scrollTop : document.body.scrollTop;

3、???

發現跑題了,不是要看一下jQuery方法的源碼嗎???不過應該大同小異。

明白了上面兩個重要的方法,實現一個兼容性良好lazyload就變得垂手可得。

相關文章
相關標籤/搜索