无限滚动、延迟加载和在线广告有什么共同点?
他们需要了解并对页面上元素的可见性做出反应!
不幸的是,传统上在 Web 上确定元素是否可见非常困难。大多数解决方案监听 scroll 和 resize 事件,然后使用 DOM API,如 getBoundingClientRect() 手动计算元素相对于视窗的位置。这通常有效,但效率低下,并且没有考虑元素可见性发生变化的其他方式,例如页面上方的较大图像最终加载完毕,从而将所有其他内容向下推。
对于广告来说,情况变得更糟,因为涉及到真金白银。正如 Malte Ubl 在 他的演讲 中所解释的那样,广告商不想为从未显示的广告付费。为了确保他们知道广告何时可见,他们用数十个微小的、单像素的 Flash 电影来覆盖广告,可以从它们的帧速率推断出它们的可见性。在没有 Flash 的平台上,例如智能手机,广告商会设置计时器来强制浏览器每隔几毫秒重新计算每个广告的位置。
这些技术会降低性能、消耗电池,并且如果浏览器可以通知我们元素的可见性何时发生变化,那么这些技术将是完全不必要的。
这就是 IntersectionObserver 的作用。
您好,新的 IntersectionObserver()
在最基本的情况下,IntersectionObserver API 看起来像这样
let observer = new IntersectionObserver(handler);
observer.observe(target); // <-- Element to watch
下面的 演示 显示了一个简单的处理程序在实际中的作用。
单个观察者可以同时观察多个目标元素;只需对每个目标重复调用 observer.observe()
。
交叉?我以为这是关于可见性的?
默认情况下,IntersectionObservers 计算目标元素与页面可见部分(也称为浏览器的“视窗”)的重叠程度(或“与…相交”):
但是,观察者还可以监控元素与任意父元素的重叠程度,而无论实际的屏幕可见性如何。这对于按需加载内容的小部件很有用,例如容器 div
内的无限滚动列表。在这种情况下,小部件可以使用 IntersectionObservers 来帮助加载足够的内容以填充其容器。
为简单起见,本文的其余部分将以“可见性”来讨论事物,但请记住,IntersectionObservers 不一定局限于字面上的可见性。
处理程序基础
观察者处理程序是回调函数,它们接收两个参数
- 一个 IntersectionObserverEntry 对象列表,每个对象都包含有关自上次调用处理程序以来目标交叉点如何变化的元数据。
- 对观察者本身的引用。
观察者默认监控浏览器的视窗,这意味着上面的演示只需要查看 isIntersecting
属性来确定目标元素的任何部分是否可见。
默认情况下,处理程序仅在目标元素从完全屏幕外过渡到部分可见或反之亦然时运行,但是如果您想区分部分可见和完全可见的元素怎么办?
阈值来救援!
使用阈值
除了处理程序回调之外,IntersectionObserver 构造函数还可以接受一个包含观察者几个配置选项的对象。其中一个选项是 threshold
,它定义了调用处理程序的断点。
let observer = new IntersectionObserver(handler, {
threshold: 0 // <-- This is the default
});
默认的 threshold
为 0
,只要目标变得部分可见或完全不可见就会调用处理程序。将 threshold
设置为 1
会在目标在完全可见和部分可见之间切换时触发处理程序,而将其设置为 0.5
会在目标经过 50% 可见性点时触发处理程序,无论方向如何。
您还可以提供一个阈值数组,如下面的 演示 中的 threshold: [0, 1]
所示
缓慢滚动目标进出视窗,并观察其行为。
目标从完全可见开始 - 它的 intersectionRatio
为 1
- 并且在它从屏幕上滚动出去时发生两次变化:一次变为类似 0.87
,然后变为 0
。当目标滚动回到视图中时,它的 intersectionRatio
更改为 0.05
,然后更改为 1
。0
和 1
有道理,但额外的值来自哪里,以及 0
和 1
之间的其他所有数字呢?
阈值是根据过渡定义的:只要浏览器注意到目标的 intersectionRatio
已经超过或缩小到某个阈值,就会触发处理程序。将阈值设置为 [0, 1]
告诉浏览器“只要目标跨越无可见性 (0
) 和完全可见性 (1
) 的界限,就通知我”,这实际上定义了三种状态:完全可见、部分可见和不可见。
观察到的 intersectionRatio
值因测试而异,因为浏览器必须等待空闲时刻才能检查并报告交叉点;这些计算在后台发生,优先级低于滚动或用户输入等操作。
尝试 编辑 CodePen 以添加或删除阈值。观察当处理程序运行时和运行位置的变化。
其他选项
IntersectionObserver 构造函数可以接受另外两个选项
root
:要观察的区域(默认值:浏览器视窗)。rootMargin
:在计算交叉点时缩小或扩展根节点的逻辑大小的程度(默认值:"0px 0px 0px 0px"
)。
更改 root
允许观察者检查相对于父容器元素的交叉点,而不仅仅是浏览器的视窗。
增加观察者的 rootMargin
可以检测目标何时接近给定区域。例如,观察者可以在即将变得可见之前等待加载屏幕外图像。
浏览器支持
IntersectionObserver 在 Edge 15、Chrome 51 和 Firefox 55 中默认可用,Firefox 55 预计在下周发布。
一个 polyfill 可用,它在所有地方都有效,尽管没有本地实现的性能优势。
其他资源
关于 Dan Callahan
Mozilla 开发者关系工程师,前 Mozilla Persona 开发人员。
8 条评论