跟踪元素可视?试试Intersection Observer

网站建设4年前发布
67 0 0

现在有以下几种场景。
,对于这些传统的实现方法是,监听到scroll事件后,调用目标元素的getBoundingClientRect()方法,得到它对应于视口左上角的坐标,再判断是否在视口之内。这种方法的缺点是,由于scroll事件是同步事件,在滚动时密集发生,计算量很大,容易造成性能问题。经常需要配合节流一起使用。
,这时候 Intersection Observer 就可以优秀的解决我们上述问题。
,getBoundingClientRect()(地址:https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect)
,Intersection Observer是w3c提出的一种 Observer API,属于浏览器中全局可访问对象,Intersection Observer 能够更好地支持上述场景,因为 Observer 并不在主线程中执行,降低了资源消耗,优化了网页性能。
,Intersection Observer为web开发者提供了一种异步查询元素相对于其他元素或窗口位置的能力。它常应用于解决追踪一个元素在窗口的可视问题。
,注:一旦 IntersectionObserver 被创建,则无法更改其配置,所以一个给定的观察者对象只能用来监听可见区域的特定变化值;但是,你可以在同一个观察者对象中配置监听多个目标元素。
,options 为可选参数。,未指定时,observer实例默认使用文档视口作为root,margin为0,阈值为0%。(即一像素的改变都会触发回调函数)
,可以配置的参数有三个:
,2023030601254626963f88882b5d9d6eb2443c97ce03303f0fec169,callback:当元素可见比例超过指定阈值(threshold)后,会调用回调函数,此回调函数接受两个参数:,entries:一个IntersectionObserverEntry对象组成的数组。intersectionObserverEntry提供目标元素的信息,有以下六个属性:,202303060125482162253593b8960efae3277aa2185df6827c0d541,observer:被调用的IntersectionObserver实例。,IntersectionObserver地址:https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
,202303060125487324fc8058020cb2a5015326380e6337353974360,我们在使用该api时,一定要判断浏览器是否支持,如果不支持,需要我们引入pollify来解决, 我们本篇主要介绍:Intersection Observer polyfill的原理,来了解一下其具体实现。
,对Intersection Observer底层源码感兴趣的同学可以看:intersection observe实现  ,intersection observe实现地址:https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/renderer/core/intersection_observer/intersection_observer.cc
,observe方法定义在IntersectionObserver原型上,该函数接收的参数就是我们需要监测的dom元素(目标元素)。
,首先会遍历this._observationTargets数组,这步就是为了判断当前的元素是否已经通过observe方法监测过。如果已经监测过,(isTargetAlreadyObserved为true)就直接return,防止同一个observer实例对同一个target元素进行多次监测。
,如果没有监测过target元素,这里会对target的类型进行判断。如果不是一个dom结点(nodeType !== 1),同样会抛出一个错误。
,顾名思义,如果我们的observe实例不存在,即将该实例加入到全局registry数组中,避免被垃圾回收机制回收。
,该函数主要用来实现对目标元素的检测,可以看下具体实现,摘除了一些边界值判断的逻辑,如判断dom已经销毁,判断重复监听等,直接看核心逻辑,实现监听的方式有两种
,上述的_monitorIntersections中有四个地方调用了_checkForIntersection
,还有就是第一个讲解的observe函数中,作为callback回调触发。
,该函数的作用是,判断root和target的交集是否发生变化,发生变化则触发observe的回调。,this._observationTargets这个属性用来保存被observer所监听的所有的target元素。
,_getRootRect是获取root元素的区域,这个区域是rootRect和rootMargin结合计算出新的rootRect区域的大小。,接着遍历this._observationTargets。
,在这个forEach遍历中,主要动作就是:搜集root元素和target元素的交集状态,并把他们存入到_queuedEntries数组中。
,而计算目标元素和root元素相交区域的核心就是 _computeTargetAndRootIntersection函数
,这里判断如果元素是隐藏的,则不可能会相交,直接return。
,通过atRoot标志位,判断while循环是否循环到了this.root或者是document。
,如果我们采用默认的root即document,而且parentNode就是document,那么循环将会进入if分支,并将parentRect被赋值为rootRect,atRoot设置为true。接着执行第44行代码逻辑。
,computeRectIntersection 函数,这里就是在计算两个区域rect1和rect2的交集
,红框部分即相交部分的区域~,202303060125486100f0489d4d9f333408490dbb203c9b8a2b0f237,如果target.parentNode不是document,那么while循环会执行else分支。其中执行else分支有一个条件parentComputedStyle.overflow != 'visible'。如果parentComputedStyle.overflow的值为visible,那么target和root最大的交叉面积就是target的大小。
,交叉面积算出来之后,使用IntersectionObserverEntry函数计算出各个属性值,然后计算出intersectionRatio和isIntersecting的值。
,到这里,_checkForIntersections函数第11行的遍历完成啦
,遍历完成,后面还有两行逻辑~,this._queuedEntries 是一个数组,其中每一个元素都是IntersectionObserverEntry实例对象。只有当这个属性的长度大于 0 的时候,才会触发回调函数。
,回调函数第一个参数是this.takeRecords()获取到的值,回忆一下上面讲解intersection observe概念的时候,我们说过callback回调的第一个参数entrys,是由IntersectionObserverEntry对象组成的数组,他就是takeRecords方法的返回值,那么takeRecords方法做了什么~,方法实现很简单,使用数组的slice方法对this._queuedEntries进行了一个拷贝,然后清空了this._queuedEntries。我们知道,intersection observe的回调触发和takeRecords的调用都可以用来获取entries(IntersectionObserverEntry对象数组),每个对象的目标元素都包含每次相交的信息,可以显式通过调用takeRecords方法或隐式地通过观察者的回调(oberve的callback第一个参数)自动调用。当我们调用takeRecords后,有一步清空操作,可以看出如果显示调用takeRecords,则callback不会再被调用。
,IntersectionObserverEntry地址:https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserverEntry
,引用官网的一句话就是:
,调用此方法会清除挂起的相交状态列表,因此不会运行回调,以上是处理所有 Observer 的主体逻辑啦。,Intersection Observer, version 2 目前兼容性还不是很好,期待未来征服各主流浏览器,20230306012555d2b7cf111a12473835a872942900507c2a0fe1101,我们不禁要思考,v1版有哪些不足?
,Intersection Observer v1 API 可以告诉您元素何时滚动到窗口的视口中,但它不会告诉您该元素是否被任何其他页面内容覆盖(即元素何时被遮挡)或该元素的可视显示已被 transform,opacity有效filter等css属性修改地使其不可见。
,Intersection Observer v2 引入了跟踪目标元素的实际“可见性”的概念,就像人类定义的那样。IntersectionObserver通过在构造函数中设置一个选项,相交的IntersectionObserverEntry实例将包含一个名为 isVisible的新布尔字段,isVisible是true,即目标元素完全不被其他内容遮挡,并且没有应用会改变或扭曲其在屏幕上的显示的视觉效果。相反,一个false意味着不能保证。
,附上pollify完整源码的github地址:intersection observe pollify源码(地址:https://github.com/GoogleChromeLabs/intersection-observer/blob/main/intersection-observer.js)

© 版权声明

相关文章