Intersection Observer 笔记

有时候我们需要根据一个元素的位置来修改它的属性,比如图片的 lazyload,比如视频离开视窗之后停止播放。

以前的做法通常是:

  1. 侦听 window.scroll 事件
  2. scroll 触发,遍历每个要检查的 DOM Element,执行 .getBoundingClientRect() 取出它的 widthheighttopleft,然后根据 viewport 和宽高 scrollTop scrollLeft 计算对象是否应该出现
  3. 然后做处理

这样做会产生一些问题:

  1. 如果漏掉移除侦听器,可能造成内存泄漏
  2. 不同组件之间,很难共享侦听器
  3. 每一次都计算所有 Element,成本很高

于是现在我们有了 Intersection Observer,专门用来观察一个 Element 是否出现在 viewport 或者父容器里。它可以很好的解决这些问题:

  1. API 更清晰
  2. 逻辑原生,速度更快,消耗更少
  3. 可以自定义阈值,更加可控

关于 Intersection Observer 的详细知识,建议大家认真阅读 MDN – Intersection Observer,我就不抄文档了。

使用 Intersection Observer 大体上分为三步:

  1. 声明一个 Intersection Observer 实例,这一步最关键的是要确定显隐依据哪个元素,也就是 root
  2. 将需要检查的元素加入侦听队列
  3. 在回调函数里处理元素状态

写成代码大概是这样的:

// 声明一个实例
// 因为我的视口即当前 viewport,所以这里不需要 `options`
const observer = new IntersectionObserver(entries => {
  // 遍历所有实例,如果它显示出来,即 intersectionRatio 显示比例大于 0
  // 那么就让它 `dispatch('visible')`
  entries.forEach(({target, intersectionRatio}) => {
    const event = new CustomEvent('visible', {
      detail: {
        isVisible: intersectionRatio > 0,
      },
    });
    target.dispatchEvent(event);
  });
});

// 然后可以在 Vue 里侦听这个事件
export default {
  template: '<div @visible="onVisible"></div>',
  mounted() {
    observer.observe(this.$el);
  },
  beforeDestroy() {
    observer.unobserve(this.$el);
  },
}

Intersection Observer API 公布一段时间之后,又进行了升级,现在支持更丰富的参数,比如我们可以定义一个函数去判断更复杂情况下的显示状态。不过大部分场景下,我们并不需要很精准的判断,所以我觉得这个只是保障选择的机会。


参考阅读:

Proposed Updates for Intersection Observer

如果您觉得文章内容对您有用,不妨支持我创作更多有价值的分享:


已发布

分类

来自

评论

欢迎吐槽,共同进步

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据