Better

Ethan的博客,欢迎访问交流

Observer in Browser

浏览器提供的 Observer api。

背景

对于不是由用户直接触发的事件,有没有什么办法可以检测得到呢,如元素从不可见到可见、元素大小的改变、元素的属性和子节点的修改等,浏览器提供了如下 api。

  • MutationObserver
  • IntersectionObserver
  • PerformanceObserver
  • ResizeObserver
  • ReportingObserver

MutationObserver

有点类型于监听一个普通 JS 对象的变化,我们会用 Object.defineProperty 或者 Proxy,当我们需要监听 dom 元素变化时,可以使用 MutationObserver 监听元素的属性和子节点的变化。简单使用如下

const mutationObserver = new MutationObserver((mutationsList) => {
    console.log(mutationsList)
});

mutationObserver.observe(box, {
    attributes: true,
    childList: true
});

使用场景:强制某个元素不允许删除,如水印。

IntersectionObserver

用于监听一个元素从不可见到可见,从可见到不可见。简单使用如下

const intersectionObserver = new IntersectionObserver(
    function (entries) {
        console.log('info:');
        entries.forEach(item => {
            console.log(item.target, item.intersectionRatio)
        })
    }, {
        threshold: [0.5, 1] // 表示可见比例 0.5 和 1 时分别进行触发
    }
);

intersectionObserver.observe(domElement);

使用场景:图片懒加载、无限滚动。

PerformanceObserver

浏览器提供了 performance 的 api 用于记录一些时间点、某个时间段、资源加载的耗时等。搭配 PerformanceObserver 于监听记录 performance 数据的行为,一旦记录了就会触发回调,这样我们就可以在回调里把这些数据上报。

const performanceObserver = new PerformanceObserver(list => {
    list.getEntries().forEach(entry => {
      console.log(entry);// 上报
    })
});
performanceObserver.observe({entryTypes: ['resource', 'mark', 'measure']});

ResizeObserver

窗口我们可以用 addEventListener 监听 resize 事件,元素则可以用 ResizeObserver 监听大小的改变,当 width、height 被修改时会触发回调。简单使用如下

const resizeObserver = new ResizeObserver(entries => {
    console.log('当前大小', entries)
});
resizeObserver.observe(box);

ReportingObserver

用于捕捉浏览器自带的干预行为

  • 当浏览器运行到过时(deprecation)的 api 的时候,会在控制台打印一个过时的报告
  • 浏览器还会在一些情况下对网页行为做一些干预(intervention),比如会把占用 cpu 太多的广告的 iframe 删掉
  • 会在网络比较慢的时候把图片替换为占位图片,点击才会加载

这些干预或者过时的 api 并不是报错,所以不能用错误监听的方式来拿到,此时可以使用 ReportingObserver,简单使用如下

const reportingObserver = new ReportingObserver((reports, observer) => {
    for (const report of reports) {
        console.log(report.body);//上报
    }
}, {types: ['intervention', 'deprecation']});

reportingObserver.observe();

更多



留言