js

三个比较有用的Observer

Posted by Lauginwing on June 5, 2020

IntersectionObserver

  • 目标(target)元素和根(root)元素的交集大小超过阈值(threshold)规定的大小时候,执行回调函数。IntersectionObserver API 是异步的,不会随着目标元素的滚动同步触发。

  • 配置项

1
2
3
4
5
{
    root: document.body,  // 所观察对象的具体祖先元素(element)。如果未传入值或值为null,则默认使用顶级文档的视窗。
    rootMargin: "0px 0px 0px 0px", // 计算交叉时添加到根(root)边界盒bounding box的矩形偏移量, 可以有效的缩小或扩大根的判定范围从而满足计算需要。
    thresholds: [0, 0.5, 1] // 一个包含阈值的列表,当观察对象的任何阈值被越过时,都会执行回调
}
  • 文档

  • 兼容性:ios 12.2,Android 4.4,chrome 51

  • polyfill:intersection-observer, 基于 scroll 和 resize 事件实现。

  • 使用实例:1. 固顶 2. 懒加载 3. 滚动到底部加载

MutationObserver

  • 在指定的 DOM 发生变化时执行回调函数。

  • 他的回调是 microTask,旧版 vue 曾使用MutationObserver实现 nextTick(没有 promise 的时候):

1
2
3
4
5
6
7
8
9
10
var counter = 1;
var observer = new MutationObserver(nextTickHandler);
var textNode = document.createTextNode(String(counter));
observer.observe(textNode, {
  characterData: true,
});
timerFunc = () => {
  counter = (counter + 1) % 2;
  textNode.data = String(counter);
};
  • 配置项
1
2
3
4
5
6
7
8
9
10
11
// 前三项中必须要有一项为true,否则会抛错
{
    childList: true,  // 观察目标子节点的变化,是否有添加或者删除
    attributes: true, // 观察属性变动
    characterData: true, // 监视指定目标节点或子节点树中节点所包含的字符数据的变化

    subtree: true,    // 观察所有后代节点
    attributeFilter: ['id'], // 要监视的特定属性名称的数组,不在此数组中的属性变化时将被忽略;未设置此属性的则观察所有属性变动
    attributeOldValue: true,  // 当监视节点的属性改动时,是否记录改动前的值
    characterDataOldValue: true // 当监视节点的文本改动时,是否记录改动前的值
}
  • 文档

  • 兼容性:ios 7,Android 4.4,chrome 51,IE 11 (移动端放心使用)

  • polyfill:mutationobserver-shim

  • 使用实例:1.修复 ios12 下软键盘顶起页面后,收起软键盘,页面位置不恢复的 bug;(在初始化应用时,设置观察器:当有 input 元素新增时,给该 input 元素添加 blur 事件,失去焦点时,滚动视窗。适用于客户端渲染的场景)

ResizeObserver

  • 元素的尺寸变化时,触发回调。

  • 文档

  • 兼容性:chrome 66, ios 和安卓都没有实现

  • polyfill: ResizeObserver Polyfill (基于 MutationObserver~)

  • 使用例子:拖动缩放 textarea 元素,内容显示其当前的长宽