使用交叉观察器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 事件则需要手动计算元素的位置,实现起来相对复杂并且性能较差。
相关推荐
逐·風36 分钟前
unity关于自定义渲染、内存管理、性能调优、复杂物理模拟、并行计算以及插件开发
前端·unity·c#
Devil枫1 小时前
Vue 3 单元测试与E2E测试
前端·vue.js·单元测试
尚梦2 小时前
uni-app 封装刘海状态栏(适用小程序, h5, 头条小程序)
前端·小程序·uni-app
GIS程序媛—椰子2 小时前
【Vue 全家桶】6、vue-router 路由(更新中)
前端·vue.js
前端青山3 小时前
Node.js-增强 API 安全性和性能优化
开发语言·前端·javascript·性能优化·前端框架·node.js
毕业设计制作和分享3 小时前
ssm《数据库系统原理》课程平台的设计与实现+vue
前端·数据库·vue.js·oracle·mybatis
程序媛小果3 小时前
基于java+SpringBoot+Vue的旅游管理系统设计与实现
java·vue.js·spring boot
从兄4 小时前
vue 使用docx-preview 预览替换文档内的特定变量
javascript·vue.js·ecmascript
凉辰4 小时前
设计模式 策略模式 场景Vue (技术提升)
vue.js·设计模式·策略模式
清灵xmf5 小时前
在 Vue 中实现与优化轮询技术
前端·javascript·vue·轮询