面试官:你利用过IntersectionObserve办法吗?怎么用?

刚刚阅读1回复0
kewenda
kewenda
  • 管理员
  • 注册排名1
  • 经验值161130
  • 级别管理员
  • 主题32226
  • 回复0
楼主

媒介

不晓得你有没有碰到过如许的问题:若何实现图片懒加载?若何判断元素进入了可视区?若何判断元素不在可视区内?等等......

那些问题我相信绝大大都的前端小伙伴都碰到过,并且在项目中的碰到的频次还不低!我们就拿图片懒加载那种场景举例:当图片进入可视区后才停止加载。常见的做法就是通过监听 scroll 滚动事务,然后通过 getBoundingClientRect()实时获取元素的相对位置,从而判断元素能否呈现在可视区内。

上面的办法需要频繁触发 scroll 事务,很容易形成卡顿或者页面性能问题。

处置那种问题,我们能够利用另一种体例:IntersectionObserve 办法。

1.认识 IntersectionObserve

IntersectionObserve 是阅读器供给的一个原生构造函数,它也被称做穿插察看器。 它能够察看我们的元素能否可见,也就是能否和可视区发作穿插。

官网的解释:

IntersectionObserver 接口供给了一种异步察看目的元素与其祖先元素或顶级文档视窗(viewport)穿插形态的办法。祖先元素与视窗(viewport)被称为根(root)。

官网说的略微晦涩一点,我们通俗的给各人解释一下,连系一张图应该就很好里面了。

通俗的解释:

我们能够利用 IntersectionObserver 接口察看一个元素,察看它能否进入了可视区,那个可视区能够相关于视窗或者祖先元素。

看图理解:

上面的图就很形象的描述了一个元素逐渐呈现在可视区内的过程,当元素和可视区发作穿插时,则代表进入可视区内了。而我们的 “穿插察看器” IntersectionObserve 就和名字一样,专门用来察看何时穿插。

2.根本利用

IntersectionObserve 利用起来很简单,我们领会了它领受的参数以及照顾的办法若何利用后,即可以很快的上手。

2.1 初始化实例

因为它是一个构造函数,所以我们能够利用 new 的体例实例化它,代码如下:

<script> let IO = new IntersectionObserver(callback, options); </script>

该构造函数领受两个参数:

callback:回调函数,当元素的可见性发作变革,即元素与目的元素订交发作改动时会触发该回调函数。options:一些设置装备摆设项参数,若是不传会有默认值,它能够用来设置装备摆设可视区元素、什么时候触发还调等等,默认就是阅读器视口。

2.2 回调函数参数

callback 会领受两个参数,次要解释如下:

entries:

它是一个 IntersectionObserverEntry 对象数组 ,IntersectionObserverEntry 次要存储的是一些察看元素的信息,次要有以下 7 个属性:

time:可见性发作变革的时间,是一个高精度时间戳,单元为毫秒

target:被察看的目的元素,是一个 DOM 节点对象

rootBounds:根元素的矩形区域的信息,getBoundingClientRect()办法的返回值,若是没有根元素(即间接相关于视口滚动),则返回 null

boundingClientRect:目的元素的矩形区域的信息

isIntersecting:目的元素当前能否可见 Boolean 值 可见为 true

intersectionRect:目的元素与视口(或根元素)的穿插区域的信息

intersectionRatio:目的元素的可见比例,即 intersectionRect 占 boundingClientRect 的比例,完全可见时为 1,完全不成见时小于等于 0

observer:

它返回的是被挪用的 IntersectionObserve 实例,我们凡是无需操做。

2.3 options 设置装备摆设

options 是构造函数的第二个参数,是一个对象的形式,它次要一些设置装备摆设信息,次要设置装备摆设项有如下几个:

root:

次要用来设置装备摆设被察看元素是相关于谁可见和不成见,若是不设置装备摆设,则默认的是阅读器视口。

threshold:

次要用来设置装备摆设两个元素的穿插比例,它是一个数组,用于决定在什么时候触发还调函数。

rootMargin:

用来改动可视区域的范畴,假设我们可视区域大小是 300x300,能够通过该参数改动可视区域大小,但是现实像素值并没有变,长处类似于我们上拉加载更多场景:当间隔底部几几像素的时候就加载。

看图理解:

示例代码:

let viewport = document.getElementById("viewport"); // 可视区域 let options = { root: viewport, threshold: [0, 0.5, 1], rootMargin: 30px 100px 20px }

2.4 实例办法

初始化实例后,我们就能够挪用实例办法了。IntersectionObserver 实例常用的办法常次要有下面几个:

IO.observe([element]):利用该办法后代表我们起头察看某个元素了,它领受一个元素节点做为参数,也就是被察看元素。IO.unobserve([element]):该办法用于停行察看某元素,同样领受一个元素节点做为参数。IO.disconnect():该办法用于封闭察看器。

能够先简单演示一下,看看何时触发 callback。

3.代码演示

3.1 查看 entries 和 observe

我们先来看一下回调函数里面默认传递的参数打印出来是什么:entries 和 observe。

示例代码:

<head> <style> .viewport { width: 300px; height: 200px; border: 1px solid blue; overflow: auto; } .box1 { height: 600px; width: 100%; } .observed { width: 100px; height: 100px; border: 1px solid green; } </style> </head> <body> <div class="viewport" id="viewport"> <div class="box1"> <div class="observed" id="observed"></div> </div> </div> </body> <script> let viewport = document.getElementById("viewport"); // 可视区域 let observed = document.getElementById("observed"); // 被察看元素 let options = { root: viewport, // 指定可视区元素 } let IO = new IntersectionObserver(IOCallback, options); // 初始化实例 IO.observe(observed); // 起头察看 // 回调函数 function IOCallback(entries, observer) { console.info("entries", entries); console.info("observer", observer); } </script>

界面显示:

输出成果:

那里的代码还比力简单,我们那里设置了视图窗口为我们指定的 id 为 viewport 的元素,被察看元素为 id 为 observed 的元素。当我们刷新页面的时候,IOCallback 回调函数便会施行,且打印了 entries 和 observe,至于它们中每个参数代表的意义各人能够参照上一节。

3.2 实现图片懒加载

图片懒加载是我们十分常见的一个场景了,那里我们拿那个场景间隔相信各人能够愈加容易理解。

需求布景:

我们有十分多的图片,若是一次性全数衬着,十分消耗性能。所以我们需要实现图片呈现在可视区域内后在停止衬着加载。

实现思绪:

先确定可视区窗口为所有 img 标签添加一个自定义 data-src 属性,用来存放图片实正途径操纵 IntersectionObserve 察看每一张图片能否进入可视区内若是进入可视区内,则将图片的 src 途径替代为实正的 data-src 途径

示例代码:

<head> <style> .viewport { width: 300px; height: 200px; border: 1px solid blue; overflow: auto; } .box1 { height: 600px; width: 100%; } .observed { width: 100px; height: 100px; border: 1px solid green; } .imgs { width: 100px; height: 100px; } </style> </head> <body> <div class="viewport" id="viewport"> <div class="box1"> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> <img src="./place.jpg" data-src="http://p8.qhimg.com/bdr/__85/t01e5f605262fb61fb4.jpg" alt="图片" class="imgs" /> </div> </div> </body> <script> let viewport = document.getElementById("viewport"); // 可视区域 let imgList = document.querySelectorAll(".imgs"); // 被察看元素 let options = { root: viewport } let IO = new IntersectionObserver(IOCallback, options); // 轮回所有 img 标签,使它被察看 imgList.forEach((item) => { IO.observe(item) }) // 回调函数 function IOCallback(entries, observer) { // 轮回所有察看元素 entries.forEach(item => { // 若是呈现在可视区内,则替代 src if (item.isIntersecting) { console.info("呈现在可视区内") item.target.src = item.target.dataset.src // 替代 src IO.unobserve(item.target) // 停行察看当前元素 制止不成见时候再次挪用 callback 函数 } }); } </script>

上段代码中我们定义了良多图片标签,每张图片都设置了一个默认 src,那个 src 不是实在的图片地址,data-src 属性存放的实在图片地址。在现实项目中,./place.jpg 应该是图片未加载出来时显示的默认效果,那里为了简单,我间接利用了一张图片,项目中能够用 icon 替代。

输入成果:

我们会发现当图片没有呈现可视区域内时,src 仍是虚假的图片地址,当我们滚动列表时,图片逐渐替代为实在地址,如许就实现了图片的懒加载。

上述列子固然不敷严谨,但是大要可以表示出图片懒加载的实现原理。

4.兼容性

IntersectionObserve 在前几年似乎没有被重视,因为它存在兼容性问题,但是跟着阅读器的更新晋级,我们能够安心的利用它了。

兼容性:

警告:

IE 不兼容

总结

IntersectionObserve 在有些场景下能够说长短常的便利了,那个 API 其实不难,次要是里面的属性和参数不太好记,但是只要我们理解了原理,记忆起来应该也不难。

做者:小猪课堂

链接:面试官:你利用过IntersectionObserve办法吗?怎么用?来源:稀土掘金

我建了一个前端小白交换群,我会给各人分享我搜集整理的各类进修材料,组织各人一路做项目操练,帮忙各人婚配一位进修伙伴互相监视进修,欢送参加。

0
回帖 返回软件

面试官:你利用过IntersectionObserve办法吗?怎么用? 期待您的回复!

取消
载入表情清单……
载入颜色清单……
插入网络图片

取消确定

图片上传中
编辑器信息
提示信息