掌握Intersection Observer API,轻松实现实现图片懒加载、元素滚动动画、无限滚动加载等功能

举报
watermelo37 发表于 2025/04/30 16:50:14 2025/04/30
【摘要】         作者:watermelo37        CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。        一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。------------------------------------------...

        作者:watermelo37

        CSDN万粉博主、华为云云享专家、阿里云专家博主、腾讯云、支付宝合作作者,全平台博客昵称watermelo37。

        一个假装是giser的coder,做不只专注于业务逻辑的前端工程师,Java、Docker、Python、LLM均有涉猎。


---------------------------------------------------------------------

温柔地对待温柔的人,包容的三观就是最大的温柔。

---------------------------------------------------------------------


掌握Intersection Observer API,轻松实现实现图片懒加载、元素滚动动画、无限滚动加载等功能



一、什么是 Intersection Observer API?


        Intersection Observer API 是浏览器提供的一个强大接口,用来异步观察一个元素是否进入(或者离开)另一个元素或视口(viewport)的可视范围。

        通俗地说就是:"我想知道某个元素什么时候滚动到屏幕上了。"

        而且,它不会阻塞主线程,性能非常好。


二、为什么需要 Intersection Observer?


        在它出现之前,通常我们需要这么做:

window.addEventListener('scroll', function () {
  const rect = element.getBoundingClientRect();
  if (rect.top < window.innerHeight && rect.bottom > 0) {
    console.log('元素进入可视区了');
  }
});

        这种方法有什么缺点?

  • 频繁触发 scroll 事件,性能差

  • 手动判断元素位置,代码复杂

  • 在复杂页面,滚动卡顿很明显。

        Intersection Observer 在浏览器底层优化,异步触发并自动判断是否进入可视区,调用简单优雅,完美解决了这些问题!


三、Intersection Observer 如何使用


1、Intersection Observer 基本用法

        先来一份最基础的例子:

// 1. 创建观察器
const observer = new IntersectionObserver((entries, observer) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      console.log('元素进入视口');
      observer.unobserve(entry.target); // 停止观察(可选)
    }
  });
}, {
  root: null, // null 代表视口
  threshold: 0.1 // 触发时元素可见10%
});

// 2. 选中目标元素
const target = document.querySelector('.target');

// 3. 开始观察
observer.observe(target);

2、图片懒加载

        以前:图片一股脑加载 → 网速慢 + 用户体验差

        现在:图片快滚到屏幕再加载,省流量 + 加速首屏!

<template>
  <div>
    <img
      v-for="(img, index) in images"
      :key="index"
      :data-src="img"
      src="placeholder.jpg"
      class="lazy-image"
      ref="lazyImages"
      alt="Lazy Load Image"
    />
  </div>
</template>
<style scoped>
.lazy-image {
  width: 100%;
  height: auto;
  display: block;
  margin-bottom: 20px;
}
</style>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

const images = [
  '/img1.jpg',
  '/img2.jpg',
  '/img3.jpg',
  // 更多图片
];

const lazyImages = ref([]);

let observer;

onMounted(() => {
  observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        const img = entry.target;
        img.src = img.dataset.src;
        observer.unobserve(img);
      }
    });
  });

  lazyImages.value.forEach(img => {
    observer.observe(img);
  });
});

onBeforeUnmount(() => {
  if (observer) {
    observer.disconnect();
  }
});
</script>

3、元素入场动画

        滚动到元素时添加 .show 类名,播放动画。

<template>
  <div>
    <div
      v-for="(item, index) in 5"
      :key="index"
      ref="animatedElements"
      class="fade-in"
    >
      内容 {{ index + 1 }}
    </div>
  </div>
</template>

<style scoped>
.fade-in {
  opacity: 0;
  transform: translateY(30px);
  transition: all 0.6s ease;
}
.fade-in.show {
  opacity: 1;
  transform: translateY(0);
}
</style>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

const animatedElements = ref([]);

let observer;

onMounted(() => {
  observer = new IntersectionObserver((entries) => {
    entries.forEach((entry) => {
      if (entry.isIntersecting) {
        entry.target.classList.add('show');
        observer.unobserve(entry.target);
      }
    });
  }, {
    threshold: 0.2
  });

  animatedElements.value.forEach(el => {
    observer.observe(el);
  });
});

onBeforeUnmount(() => {
  if (observer) {
    observer.disconnect();
  }
});
</script>

4、无限滚动(加载更多)

        滚到底部时自动加载新数据即可,这里只给一个简单的demo,实际实现还需要考虑内存泄漏、用户操作友好性等问题。

<template>
  <div>
    <div v-for="(item, index) in list" :key="index" class="list-item">
      {{ item }}
    </div>

    <div ref="loadMoreTrigger" class="load-more">
      加载更多...
    </div>
  </div>
</template>

<style scoped>
.list-item {
  padding: 10px;
  border-bottom: 1px solid #ccc;
}

.load-more {
  padding: 20px;
  text-align: center;
  color: gray;
}
</style>
<script setup>
import { ref, onMounted, onBeforeUnmount } from 'vue';

const list = ref(Array.from({ length: 20 }, (_, i) => `Item ${i + 1}`));
const loadMoreTrigger = ref(null);

let observer;

const loadMore = () => {
  const nextItems = Array.from({ length: 10 }, (_, i) => `Item ${list.value.length + i + 1}`);
  list.value.push(...nextItems);
};

onMounted(() => {
  observer = new IntersectionObserver((entries) => {
    if (entries[0].isIntersecting) {
      loadMore();
    }
  }, {
    threshold: 1.0
  });

  observer.observe(loadMoreTrigger.value);
});

onBeforeUnmount(() => {
  if (observer) {
    observer.disconnect();
  }
});
</script>


四、使用 Intersection Observer 的关键点


        总结下来就是四个关键步骤:

步骤 说明
1 用 ref 获取 DOM 元素
2

在 onMounted 中创建 IntersectionObserver

3

给需要观察的元素 .observe()

4

在 onBeforeUnmount 中 .disconnect() 清理


五、结语


        Intersection Observer API 是现代 Web 开发不可缺少的利器,掌握它,你可以轻松实现图片懒加载、元素滚动动画、无限滚动加载、页面性能优化等目的。相比传统的 scroll 事件监听能实现全面碾压。

        只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。