使用交叉观察器intersectionObserver 实现高性能下拉加载

背景

其实网上大多都是监听scroll进行实现的,确实可以,偶然发现有个intersectionObserver api, 然后就试试如何实现下拉刷新。

1、对比intersectionObserver与监听scroll性能

目前测试的是下拉加载300条数据

1-1、chrome-performance测试

我们利用chromeperformance 测试下, 。

  • intersectionObserver监听 的 performance
  • scroll监听 的 performance

1-2、数据转换为表格对比下

  • 300条数据对比
下拉加载方式 JS Heap Documents Listeners
scroll监听 12.5MB - 13.6MB 4-4 94
intersectionObserver监听 6.3MB - 7.4MB 1-2 50

使用intersectionObserver监听 , 我们可以看到内存只占用了scroll的50%, 这还是300条数据的情况下,这性能差距肯定是指数级拉开的,所以用哪个就不言而喻了。

这时候,如果你抛出,又不是不能跑, 我只能回答确实~

2、intersectionObserver介绍

  • intersectionObserver-文档
  • 说明了使用场景
    • 在页面滚动时"懒加载"图像或其他内容。
    • 实现"无限滚动"网站,在滚动过程中加载和显示越来越多的内容,这样用户就不必翻页了。
    • 报告广告的可见度,以便计算广告收入。
    • 根据用户是否能看到结果来决定是否执行任务或动画进程。

思路

思路 我们只要监听 列表最下面的dom, 判断他在不在视图内, 若在,就加载更多.

代码

js 复制代码
<script setup lang="ts">
  const requestList = ref<any>(new Array(10).fill(0).map((_, i) => i + 1))
  const loadList = ref<any>([])
  const observerElement = ref<HTMLElement | null>(null)
  onMounted(() => {
    let observer = new IntersectionObserver(
      (entries) => {
        entries.forEach((entry) => {
          /**
           * isIntersecting
           * 0 表示目标元素完全不可见。
           * 1 表示目标元素完全可见。
           * 0~1 表示目标元素部分可见
           */
          console.log(15, entry.intersectionRatio)
          if (entry.intersectionRatio >= 0) {
            console.log('进入可视区域')
            loadMore()
          } else {
            console.log('不可见')
          }
        })
      },
      {
        threshold: 0,
      },
    )
    observer.observe(observerElement.value!)
  })

  const loadMore = () => {
    console.log('------')
    if (loadList.value.length >= 100) {
      console.log('已经满100条了')
      return
    }
    loadList.value.push(...requestList.value)
  }
</script>
<template>
  <div class="p-scroll">
    <!--?列表区域-->
    <div v-for="(i, index) in loadList" :key="index" class="card">{{ i }} -- {{ index }}</div>
    <!--?IntersectionObserver监听的对象-->
    <div ref="observerElement" class="observer-element">监听的dom</div>
  </div>
</template>

<style scoped lang="scss">
  .p-scroll {
    border: solid 1px red;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    padding: 50px;
    box-sizing: border-box;
    .card {
      height: 200px;
      border: solid 1px blue;
      display: flex;
      align-items: center;
      justify-content: center;
      //@include vertical-center;
      font-size: 30px;
      // transform: translateX(100px);
      transition: 500ms;
      // opacity: 0;
      margin: 6px 0;
    }
    .show {
      transform: translateX(0);
      opacity: 1;
    }
    .observer-element {
      border: solid 1px green;
      background: green;
      color: white;
      font-size: 20px;
      height: 100px;
    }
  }
</style>

3、监听scroll的实现

推荐使用intersectionObserver.

监听scroll,下拉刷新

js 复制代码
<script setup lang="ts">
  const requestList = ref<any>(new Array(10).fill(0).map((_, i) => i + 1))
  const loadList = ref<any>([])

  /** ********************滚动监视器***********************/
  const loadMore = () => {
    console.log('------')
    if (loadList.value.length >= 100) {
      console.log('已经满100条了')
      return
    }
    loadList.value.push(...requestList.value)
  }

  loadMore()

  // ?开始观察滚动触发元素
  const contentRef = ref()
  const handleScroll = () => {
    const container = contentRef.value
    // 判断是否滚动到底部
    if (container.scrollTop + container.clientHeight >= container.scrollHeight) {
      loadMore()
    }
  }
</script>
<template>
  <div ref="contentRef" class="p-scroll" @scroll="handleScroll">
    <div v-for="(i, index) in loadList" :key="index" class="card">{{ i }} -- {{ index }}</div>
  </div>
</template>

总结

以下内容参考自chartgpt

  • IntersectionObserver 相比监听 scroll 事件,在性能上通常更高效的原因有几点:
  1. 异步执行: IntersectionObserver 是异步执行的,它使用回调函数在元素进入或离开视口时触发,而不是像监听 scroll 事件一样在每次滚动时都触发。这样可以减少回调函数的执行次数,降低了性能开销。
  2. 硬件加速: IntersectionObserver 使用浏览器底层的硬件加速技术来进行计算,因此在性能上更为高效。而监听 scroll 事件则需要频繁地进行 DOM 查询和计算,性能消耗较大。
  3. 支持懒加载: IntersectionObserver 更适合实现懒加载功能,可以精确地监听元素是否进入视口,从而实现按需加载。而监听 scroll 事件则需要手动计算元素的位置,实现起来相对复杂并且性能较差。
相关推荐
子兮曰1 天前
jev-ultrafast 深度解析:7 秒订机票的浏览器 Agent 是如何炼成的
前端·后端·agent
子兮曰1 天前
Jev 爆发一周:7 秒 Agent 背后的 System One 生态与三场争议
前端·后端·ai编程
前端小万1 天前
写公众号赚了 3000 块后,我做了一款叫 "一键成稿" 的软件
前端·微信小程序
爱勇宝1 天前
ZCode 开源 24 小时:一份没有历史的账本,回答不了"有没有偷代码"
前端·后端·chatglm (智谱)
A黄俊辉A1 天前
uniapp webview中实现 app和内嵌的H5双向通信
vue.js·json
三十而立洋1 天前
Cookie 详解:从产生到安全,一次讲透
前端·javascript
卡布鲁1 天前
把一个 Vite + Vue3 应用塞进 qiankun (React + Umi3) 主站:十个坑的复盘
前端·javascript·react.js
李少兄1 天前
JavaScript 隐式全局变量解析
javascript
honkun61 天前
vue 表格组件 vxe-table 配置 ajax 请求自动加载数据与表单查询
vue.js·vxe-table
kybs19911 天前
全球灾害数据分析可视化 毕业设计-附源码66794
vue.js·spring boot·mysql·安全·django·c#·asp.net