博客地址: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
如下内容参考自大红本 — 《JavaScript高级程序设计》,第三版,第八章
跨浏览器肯定一个窗口的大小不是一件简单的事。IE9+、Firefox、Safari、Opera和Chrome均为此提供了4个属性:innerWidth
、innerHeight
、outerWidth
、outerHeight
。在IE9+、Safari和Firefox中,outerWidth
和outerHeight
返回浏览器窗口自己的尺寸(不管是最外层的window对象仍是从某个框架访问)。在Opera中,这两个属性的值表示页面视图容器(这里所谓的“页面视图容器”指的是Opera中单个标签页对应的浏览器窗口)的大小。而innerWidth
和innerHeight
则表示该容器中页面视图区的大小(减去边框宽度)。在Chrome中,outerWIdth
和outerHeight
与innerWidth
、innerHeight
返回相同的值,即视口(viewport)大小而非浏览器窗口大小。
IE8及更早版本没有提供取得当前浏览器窗口尺寸的属性;不过,它经过DOM提供了页面可见区域的相关信息。
在IE、Firefox、Safari、Opera和Chrome中,document.documentElement.clientWidth
和document.documentElement.clientHeight
中保存了页面视口的信息。在IE6中,这些属性必须在标准模式下才有效;若是是混杂模式,就必须经过document.body.clientWidth
和document.body.clientHeight
取得相同信息。而对于混在模式下的Chrome,则不管经过document.documentElement
仍是document.body
中的clientWidth
和clientHeight
属性,均可以取得取得视口的大小。
(跑题了?? )
虽然最终没法肯定浏览器窗口自己的大小,但却能够取得页面视口的大小,以下所示:
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'
表明混杂模式。
这里以垂直方向为例。
先来看一个stackoverflow上的回答,翻译以下:
获取滚动距离的标准方法为
window.scrollY
。Chrome、Firefox、Opera、Safari及IE Edge(或更高版本)均支持此方法。若是您仅须要支持这些浏览器,使用这个属性便可。IE >= 9 支持一个相似的属性
window.pageYOffset
,为了保证兼容性,在现代浏览器中会返回与window.scrollY
相同的值,尽管它可能在某些时候被弃用。使用
document.documentElement.scrollTop
或document.body.scrollTop
的问题是,它们并非老是都被定义了滚动。例如,Chrome和Safari将滚动定义在<body>
元素,而Firefox则定义在了document.documentElement
返回的<html>
元素上。这不是标准化的,而且在将来版本的浏览器中可能会发生变化。然而,若是scrollY
和pageYOffset
不存在,则这是获取滚动位置的惟一方法。
遂总结以下:
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/Left
或document.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;
发现跑题了,不是要看一下jQuery方法的源码吗???不过应该大同小异。
明白了上面两个重要的方法,实现一个兼容性良好lazyload就变得垂手可得。