• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

运用 IntersectionObserver 达到实现图片懒加载的功能

武飞扬头像
一个没有感情的杀手
帮助257

1 前言

这篇文章的起源来自于最近的一个产品需求,相爱相杀的产品经理希望在移动端预览转码后的PDF、PPT等文件,一般而言转码后的PDF、PPT等都会生成大量的图片,这时就涉及到了图片懒加载的实现。在原有的印象中,图片懒加载的实现都是通过监听scroll事件实现:

  1. 添加自定义属性:给img标签添加data-src,值为图片的url,同时不要设置src属性
  2. 判断目标元素与视口的交叉状态:通过获取元素的getBoundingClientRect属性的top值和页面的clientHeight进行对比,如果top值小于clientHeight,则说明元素出现在可视区域之内
  3. 设置真实的src:当元素出现在可视区域内时,将真实的图片地址赋值给目标元素的src属性

但是,今天在调研的过程中发现了IntersectionObserver这个API完全贴合了我的需求(PS:是我太落后了🙈~)。下面开始进入今天的正题吧!

2 IntersectionObserver 简介

IntersectionObserver 接口 (从属于Intersection Observer API) 提供了一种异步观察目标元素与其祖先元素或顶级文档视窗 (viewport) 交叉状态的方法。祖先元素与视窗 (viewport) 被称为**根 (root)。——引用自MDN

下面这些情况都需要用到相交检测:

  • 图片懒加载——当图片滚动到可见时才进行加载
  • 内容无限滚动——也就是用户滚动到接近内容底部时直接加载更多,而无需用户操作翻页,给用户一种网页可以无限滚动的错觉
  • 检测广告的曝光情况——为了计算广告收益,需要知道广告元素的曝光情况
  • 在用户看见某个区域时执行任务或播放动画

具体的属性以及方法就不赘述了,请直接参考MDN文档

3 基础用法

 
// 回调函数
const callback =(entries, observer) => {
  entries.forEach(entry => {
    // entry.boundingClientRect
    // entry.intersectionRatio
    // entry.intersectionRect
    // entry.isIntersecting
    // entry.rootBounds
    // entry.target
    // entry.time
  });
};

// 参数配置
const options = {
  root: document.querySelector('#scrollArea'),
  rootMargin: '0px',
  threshold: 1.0
};

// 1. 实例化一个IntersectionObserver对象,并传入相应参数和回调函数
const observer = new IntersectionObserver(callback, options);

// 2. 指定一个目标元素进行观察
const target = document.querySelector('#listItem')
observer.observe(target);

// 3.销毁时,一定要取消观察对象,否则会一直监听
observer.unobserve(target);

以上提到的entry下每个属性的具体函数,请查阅MDN

4 图片懒加载的实现

由于项目中我们统一的技术栈为Vue3 Tsx,所以下面采用tsx的写法来编写。

 
import { defineComponent, ref, toRefs, PropType, onMounted, onUnmounted } from 'vue';
import styles from './index.module.scss';
import defaultImage from '@/assets/images/defaultImage.png';

export default defineComponent({
  props: {
    // 图片集合
    imagesList: {
      type: Array as PropType<string[]>,
      required: true,
    },
  },
  setup(props) {
    const { imagesList } = toRefs(props);
    const observer = ref<any>(null);
    const root = ref<HTMLElement | null>(null);

    // 监视器的回调函数
    const handlerObserve = (entries: any) => {
      entries.forEach(({ isIntersecting, target }: any) => {
        if (isIntersecting) {
          const targetImg = target.children[0];
          targetImg.src = targetImg.dataset.src;
          // 修改过src属性之后,即可移除data-src属性并且取消监视
          targetImg.removeAttribute('data-src');
          observer.value.unobserve(target);
        }
      });
    };

    // 针对图片容器添加监听器
    const addObserve = () => {
      const list = document.querySelectorAll('.image-item-observe') as NodeListOf<Element>;
      list.forEach((item: Element) => {
        observer.value.observe(item);
      });
    };

    // 初始化监视器
    const initObserve = () => {
      observer.value = new IntersectionObserver(handlerObserve, {
        root: root.value,
        rootMargin: '0px 0px 500px 0px', // 监视区向下拓展500px
      });
      addObserve();
    };

    onMounted(async () => {
      initObserve();
    });

    onUnmounted(() => {
      // 关闭观察器
      observer.value.disconnect();
    });

    return () => (
      <div ref={root} class={styles['image-list-container']}>
        {
          imagesList.value.map((item: string, index: number) => (
            <div class={`${styles['image-item-wrapper']} image-item-observe`}>
              {/* 设置一个默认的缺省图,避免在加载过程中出现白屏的现象 */}
              <img
                class={styles['image-item']}
                src={defaultImage}
                data-src={item}
                key={index}
                width="100%"
              />
            </div>
          ))
        }
      </div>
    );
  },
});

具体效果如下图所示(200张图的加载,整体看起来还是👌的):

QQ20221003-111618-HD.gif

5 结语

第一次写文章,算是迈出了第一步,希望以后能够坚持下去。就我自身而言,写文章主要是为了记录在工作中遇到的问题,以便后期的回顾和查阅。不足之处,还请大家包涵,以后请多多指教。

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanefhb
系列文章
更多 icon
同类精品
更多 icon
继续加载