1、懒加载的概念

懒加载也叫做延迟加载、按需加载,指的是在长网页中延迟加载图片数据,是一种较好的网页性能优化的方式。在比较长的网页或应用中,如果图片很多,所有的图片都被加载出来,而用户只能看到可视窗口的那一部分图片数据,这样就浪费了性能。如果使用图片的懒加载就可以解决以上问题。在滚动屏幕之前,可视化区域之外的图片不会进行加载,在滚动屏幕时才加载。这样使得网页的加载速度更快,减少了服务器的负载。懒加载适用于图片较多,页面列表较长(长列表)的场景中。

2、懒加载的特点

  • 减少无用资源的加载:使用懒加载明显减少了服务器的压力和流量,同时也减小了浏览器的负担。
  • 提升用户体验: 如果同时加载较多图片,可能需要等待的时间较长,这样影响了用户体验,而使用懒加载就能大大的提高用户体验。
  • 防止加载过多图片而影响其他资源文件的加载 :会影响网站应用的正常使用。
  • 按需加载:减少初始页面加载时间,降低服务器和客户端的资源消耗
  • 提升页面性能:通过减少初始加载的资源数量,减轻网络带宽的压力,使页面内容更快可见。
  • 兼容大多数设备与网络环境:懒加载在任何网络环境下都能有效工作,无论是低速网络还是高速网络都可以受益
  • 减少服务器压力:懒加载可以显著减少服务器的负载,因为只有用户实际需要的资源才会被请求。
  • 适用多种类型的资源:
  • 懒加载不仅适用于图片,还可以应用到视频、脚本、iframe 等各种类型的资源上。


3、懒加载的实现原理

图片的加载是由 src 引起的,当对 src 赋值时,浏览器就会请求图片资源。根据这个原理,我们使用 HTML5 的 data-xxx 属性来储存图片的路径,在需要加载图片的时候,将 data-xxx 中图片的路径赋值给src,这样就实现了图片的按需加载,即懒加载。
注意:data-xxx 中的 xxx 可以自定义,这里我们使用 data-src 来定义。

懒加载的实现重点在于确定用户需要加载哪张图片,在浏览器中,可视区域内的资源就是用户需要的资源。所以当图片出现在可视区域时,获取图片的真实地址并赋值给图片即可。


3.1、使用原生 JavaScript 实现懒加载:

知识点:

  • window.innerHeight 是浏览器可视区的高度
  • document.body.scrollTop,document.documentElement.scrollTop 是浏览器滚动的过的距离(前者在一些较旧的浏览器或处于怪异模式(quirks mode)下,document.body.scrollTop 表示页面顶部与可见区域顶部之间的距离,后者浏览器普遍支持)
  • imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离)
  • window.pageYOffset 是一个只读属性,用来获取当前页面在垂直方向上滚动的像素值。
  • 图 片 加 载 条 件 : img.offsetTop < window.innerHeight +document.body.scrollTop;

兼容性处理:

为了确保在所有浏览器中都能正确获取页面的垂直滚动距离,通常需要同时检查document.body.scrollTopdocument.documentElement.scrollTop

var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;

代码实现 

 3.2、使用 HTML5 原生 loading="lazy" 属性

现代浏览器已经支持在 <img> 标签上添加 loading="lazy" 属性来实现图片懒加载。

示例:

<img src="example.jpg" alt="example image" loading="lazy" />

浏览器会自动在图片即将出现在视口时加载。

3.3、使用 IntersectionObserver 实现图片懒加载

对于不支持 loading="lazy" 属性的浏览器,可以使用 JavaScript 的 IntersectionObserver API 来实现图片懒加载。

<template>
  <div>
    <h1>图片懒加载示例</h1>
    <div v-if="loading">加载中...</div>
    <div v-else>
      <div v-for="(image, index) in images" :key="index">
        <!-- 使用占位符作为默认图片,并动态绑定数据 -->
        <img :data-src="image.url" alt="image.name" class="lazy-image" />
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      images: [], // 存储从后端获取的图片数据
      loading: true, // 控制加载状态
      observer: null, // 保存 IntersectionObserver 实例
    };
  },
  methods: {
    // 从后端获取图片数据
    async fetchImages() {
      try {
        const response = await axios.get('/api/images'); // 获取图片数据的 API
        this.images = response.data; // 假设后端返回一个图片对象数组
        this.loading = false;

        // 在数据加载完后,初始化 IntersectionObserver
        this.initObserver();
      } catch (error) {
        console.error('加载图片数据失败:', error);
        this.loading = false;
      }
    },
    // 初始化 IntersectionObserver
    initObserver() {
      const options = {
        root: null, // 使用视口作为根
        rootMargin: '0px',
        threshold: 0.1, // 当图片 10% 出现在视口中时触发懒加载
      };

      // 创建 IntersectionObserver 实例
      this.observer = new IntersectionObserver((entries) => {
        entries.forEach(entry => {
          if (entry.isIntersecting) {
            const img = entry.target;
            img.src = img.dataset.src; // 将 data-src 设置为 src,加载图片
            this.observer.unobserve(img); // 图片加载后停止观察该图片
          }
        });
      }, options);

      // 选择所有需要懒加载的图片
      const lazyImages = document.querySelectorAll('.lazy-image');
      lazyImages.forEach(image => {
        this.observer.observe(image); // 观察每个懒加载图片
      });
    },
  },
  mounted() {
    // 组件挂载后获取数据
    this.fetchImages();
  },
  beforeDestroy() {
    // 清理 observer 防止内存泄漏
    if (this.observer) {
      this.observer.disconnect();
    }
  },
};
</script>

<style>
.lazy-image {
  width: 100%;
  height: auto;
  display: block;
  margin-bottom: 10px;
  background-color: #f3f3f3; /* 占位背景色 */
}
</style>

在这个例子中:

  • 每张图片使用 data-src 属性保存图片的真实路径。
  • 当图片接近或进入视口时,IntersectionObserver 会触发回调,将 data-src 替换为 src,开始加载图片。
  • 图片加载完成后,IntersectionObserver 停止观察该图片
3.4使用 Vue 的懒加载插件(如 vue-lazyload) 

如果你使用 Vue.js 进行开发,可以直接使用插件如 vue-lazyload 来实现懒加载。 

安装 vue-lazyload 插件:

npm install vue-lazyload --save

 在vue项目中使用

import Vue from 'vue';
import VueLazyload from 'vue-lazyload';

Vue.use(VueLazyload);

// 或者带有一些默认设置
Vue.use(VueLazyload, {
  preLoad: 1.3,
  error: 'error.png', // 加载失败时显示的图片
  loading: 'loading.gif', // 加载中显示的图片
  attempt: 1
});

在模板中使用

<template>
  <div>
    <h1>图片懒加载示例</h1>
    <div v-if="loading">加载中...</div>
    <div v-else>
      <div v-for="(image, index) in images" :key="index">
        <img v-lazy="image.url" :alt="image.name" />
      </div>
    </div>
  </div>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      images: [],   // 存放从后端获取的图片数据
      loading: true // 控制加载状态
    };
  },
  methods: {
    // 从后端获取数据
    async fetchImages() {
      try {
        const response = await axios.get('/api/images'); // 假设后端的 API 路径
        this.images = response.data; // 假设返回的数据是一个图片对象数组
        this.loading = false;
      } catch (error) {
        console.error('加载图片数据失败:', error);
        this.loading = false;
      }
    }
  },
  created() {
    // 组件创建时获取图片数据
    this.fetchImages();
  }
};
</script>

<style>
img {
  width: 100%;
  height: auto;
  margin-bottom: 10px;
}
</style>

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐