likes
comments
collection
share

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

作者站长头像
站长
· 阅读数 70

我正在参加「掘金·启航计划」

兼容性查询结果如下

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

IntersectionObserver这个api是用来监听一个dom元素是否出现在另外一个>视口元素api

以前得监听某个元素的滚动,然后不断调用 getBoundingClientRect 来判断,非常影响性能

1 简单使用

对于同一个dom,只能观察一次,不能观察多次

准备一些dom元素

 import 'bpm-mobile/build/style/init.css';
 ​
 .....
 ​
 <>
   {range(6).map(item => <div style={{ height: 50, border: '1px dashed' }} key={item}>{item}</div>)}
   <div className='test-box1' style={{ width: 100, height: 100, border: '20px double' }}>test-box1</div>
 </>

之后把这些元素放在一共200*200的视口中

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

2 实例方法

当实例化的时候,第一个参数需要传入一个方法这个参数是必须的

 new IntersectionObserver(function () { })

当实例化完成之后,会返回一个观察者对象

 const observer = new ...

这个对象上,存在四个方法

  • observe
  • unobserve
  • disconnect
  • takeRecords

2.1 observe

当创建一个交叉观察者之后,我们需要告诉观察者要观察哪个dom元素

 observer.observe(document.querySelector('.test-box1') as HTMLElement)

2.2 unobserve

用于告知观察者,不需要观察这个dom元素了

 observer.unobserve(document.querySelector('.test-box1') as HTMLElement)

2.3 disconnect

观察元素不只可以添加一个,可以添加多个元素,如下

 const doms: HTMLElement[] = []
 ​
 for (let i = 1; i < 3; i++) {
   doms.push(document.querySelector(`.test-box${i}`) as HTMLElement)
   observer.observe(doms[i - 1])
 }

在某些时候,需要去除所有dom元素的监听,可以使用 disconnect来移除所有元素监听

 observer.disconnect()

2.4 takeRecords

intersectionobserver中用处不大,在 MutationObserver中一定作用

3 callback - entries

当页面第一次的时候,绑定的第一个函数执行一次

entriesIntersectionObserver实例化时,传入的第一个函数参数的第一个参数回调,这个参数的类型是一个数组(可以监听多个dom),由如下组成

 const observer = new IntersectionObserver(
   function (entries: IntersectionObserverEntryInit[]) {
     console.log(entries[0])
   }
 )
 ​
 document.querySelector(`.test-box1`) as HTMLElement

类型定义如下:

 interface DOMRectInit {
   height?: number;
   width?: number;
   x?: number;
   y?: number;
 }
 ​
 type IntersectionObserverEntryInit = {
   target: Element;
   boundingClientRect: DOMRectInit;
   rootBounds: DOMRectInit;
   intersectionRect: DOMRectInit;
   intersectionRatio: number;
   isIntersecting: boolean;
 }[]

3.1 target

指向监听的dom元素

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

3.2 boundingClientRect

getBoundingClientRect 获取的参数一致

表示被监听的元素当前位置和尺寸信息

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

3.3 rootBounds

getBoundingClientRect 获取的参数一致

记录视口的 getBoundingClientRect 信息

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

3.4 intersectionRect

getBoundingClientRect 获取的参数一致

当监听的元素与与视口交叉的时候,可以根据这个元素,拿到交叉的尺寸

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

3.5 intersectionRatio

用于获取被监听的元素视口之间的占用比例,值为 0 - 1

  • 当元素部分显示在视口中的时候

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

  • 当元素全部显示在视口中的时候

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

  • 当元素在视口之外的时候

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

3.6 isIntersecting

如果这个值为true,表示被监听的元素显示在视口中了

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

如果这个值为false,表示被监听的元素在视口外

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

4 callback - observer

observerIntersectionObserver实例化时,传入的第一个函数参数的第二个参数回调

!!!!这个参数建议看完options再回来查看怎么使用

当触发监听之后,回调的第二个参数的值包含如下

 interface IntersectionObserver {
     // options中设置的root,没设置为null
     readonly root: Element | null;
     // options中设置的rootMargin,没设置默认为 0px 0px 0px 0px
     readonly rootMargin: string;
     // options中设置的thresholds,没设置默认为 [0]
     readonly thresholds: ReadonlyArray<number>;
   
     // 与创建的实例中存在的回调方法一致
     disconnect(): void;
     observe(target: Element): void;
     takeRecords(): IntersectionObserverEntry[];
     unobserve(target: Element): void;
 }

5 options

在初始化观察者的时候,第二个参数,可以传递一个对象 options

 new(callback: IntersectionObserverCallback, options?: IntersectionObserverInit): IntersectionObserver;

类型定义如下

 interface IntersectionObserverInit {
     root?: Element | null;
     rootMargin?: string;
     threshold?: number | number[];
 }

5.1 root

单独设置这个参数 “没什么用处”,只是作为一个标识符用于告知自己,目前正在监听的视口元素是哪一个

比如,这个时候,把所有的元素放在一个滚动列表中

 <div className='look' style={{ width: 100, height: 100, overflow: 'auto' }}>
   {range(6).map(item => <div style={{ height: 50, border: '1px dashed' }} key={item}>{item}</div>)}
   <div className='test-box1' style={{ width: 100, height: 100, border: '20px double' }}>test-box1</div>
 </div>

然后把这个dom元素的引用放到 root

 const observer = new IntersectionObserver(
   function (entries: IntersectionObserverEntryInit[], observe: IntersectionObserver) {
     console.log(observe.root)
   },
   {
     root: document.querySelector('.look') as Element
   }
 )

然后触发监听的时候,能通过 observe.root 拿到视口的dom元素

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

如果不传这个参数,拿到的就是null但交叉监听不受影响

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.2 rootMargin

5.2.1 使用

设置视口的监听访问,格式如下,必须设置四个属性,格式为 上右下左

 new IntersectionObserver(
     ......
   {
     rootMargin: '0px 0px 50px 0px',  // 正确
     // rootMargin: '0 0 50px 0',  // 错误
     // rootMargin: '50px',  // 错误
   }
 )

当设置为下面的属性之后

  rootMargin: '10px 20px 50px 30px'

原来的视口监听设置marginRoot 之后的对比

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解 全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

这样,滚动到 -50px 的位置就能触发监听了

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.2.1 rootBounds

当开发者把 rootMargin 设置为如下代码之后

 rootMargin: '10px 20px 50px 30px'

当触发监听之后,打印 entrie.rootBounds之后,发现数据变成了视口的尺寸加上了 rootMargin 设置的大小

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.2.3 root

当把这些元素塞在一个 overflow:auto 中的时候,会发现,设置的rootMargin失效了

又变成了未设置 rootMargin 之前的效果,虽然交叉监听没有出问题

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

并且,打印 rootBounds,发现,获取到的视口的尺寸还是整个视口尺寸,这明显是错误的

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

还记得root属性吗,上面说到,单独设置root没有什么效果。rootMargin需要借助 root 才能打印正常的值

设置root

 new IntersectionObserver(
     .....
   {
     root: document.querySelector('.look') as Element,
     rootMargin: '10px 20px 50px 30px'
   }
 )

这个时候,发现,打印的rootBounds正常了

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

并且设置的rootMargin也生效了

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.3 threshold

阈值,可传入一个number,也可以传入一个number数组 , 可传的值在 [0 -1] 之间

5.3.1 传入number

当设置为 0.5 的时候

 new IntersectionObserver(
   ......
   {
     threshold: 0.5
   }
 )

表示被监听的元素必须出现在视口50%以上,或小于视口50%以下的时候才会触发监听事件

  • 小于50%

当小于50%的时候, isIntersecting都为false

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

  • 大于50%

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.3.2 传入number[]

传入的是 [.3, .7]

 new IntersectionObserver(
   ......
   {
     threshold: [.3, .7]
   }
 )

概念图像如下

交叉面积不断变大

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

交叉面积不断变小

全网最全!js四大观察者之IntersectionObserver全部属性与方法详解

5.3.3 root

rootMargin需要root的数据,而threshold只与交叉面积有关,不设置root也没事

转载自:https://juejin.cn/post/7249177497191366711
评论
请登录