vue 实现图片懒加载

一:懒加载的目的

有些页面可能展示的是大量的图片,如果我们一次性加载所有图片就会浪费性能,影响用户体验,所以我们就会懒加载这些图片。即可视区域之外的图片不加载,随着页面的滚动,图片进入可视区域,则触发图片的加载显示。
优点:页面加载速度快,用户体验感更好且节省流量

二:懒加载的原理

  1. 存储图片的真实路径,把图片的真实路径绑定给一个以data开头的自定义属性data-src即可,页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片(没有请求就提高了性能)
<img  data-src="xxx" src="xxx" width="180" height="180"/> 
  1. 需要一个滚动事件,判断元素是否在浏览器窗口,一旦进入视口才进行加载,当滚动加载的时候,就把这张图片替换为真正的url地址(也就是data-src里保存的值)
  2. 等到图片进入视口后,利用js提取data-src的真实图片地址赋值给src属性,就会去发送请求加载图片,真正实现了按需加载

实现图片懒加载的多种方法的区别就在于判断元素是否进入视口的方式不同,当使用方法3和方法4时,如果发生滚动事件,会产生大量的循环和判断操作判断图片是否可视区里,因此需要用节流进行优化。

三、 实现懒加载

方法1 lazyload插件

vue2

github地址
原理
vue-lazyload的核心原理是利用了IntersectionObserver API,这是一个用于检测元素是否与视口相交的API,它可以高效地监听元素的可见性变化,并触发回调函数。
vue-lazyload在注册插件时,会创建一个全局的IntersectionObserver实例,并设置一些选项,如阈值(threshold)、根元素(root)等。然后,在绑定v-lazy指令时,会创建一个监听器(listener)对象,并将其添加到一个监听器队列(listenerQueue)中。每个监听器对象都包含了元素的相关信息,如状态(state)、图片地址(src)等。
接下来,vue-lazyload会遍历监听器队列,并调用IntersectionObserver实例的observe方法,将每个元素注册到观察者中。当元素与视口相交时,IntersectionObserver实例会触发回调函数,并传入一个entries参数,表示所有被观察的元素的状态信息。vue-lazyload会根据entries中的isIntersecting属性判断元素是否可见,如果是,则调用监听器对象的load方法,将元素的src或者style属性替换为真实的图片地址,并将该监听器对象从队列中移除。
基本用法

  1. 安装
npm i vue-lazyload@1.2.3 -S
  1. 使用
    main.ts
// 1.图片懒加载插件
import VueLazyload from 'vue-lazyload'

// 2.注册插件
Vue.use(VueLazyload, {
  //参数配置 可不填
  
  // 懒加载默认加载图片
  loading: 'xxx.png',
  // 加载失败后加载的图片
  error: 'xxx.png',
  preLoad: 1.3, // 预加载高度的比例
  attempt: 3 // 尝试加载次数
})

可选参数配置项
在这里插入图片描述

vue-lazyload提供了一个自定义指令v-lazy,可以在img标签或者任何需要设置背景图片的标签上使用它。例如:

<!-- 懒加载img标签 -->
<img v-lazy="imgUrl" />

<!-- 懒加载背景图片 -->
<div v-lazy:background-image="bgUrl"></div>

v-lazy指令接收一个字符串类型的值,表示图片的地址。如果是背景图片,需要在指令后加上:background-image修饰符。
当页面滚动时,vue-lazyload会检测元素是否进入可视区域,如果是,则替换元素的src或者style属性,从而实现懒加载。
⚠️ 若图片为循环渲染、分页显示,则必须写key值,不然切换页面后页面视图不刷新

vue3

github地址
原理与使用方法与vue2版本插件相同,仅安装不同

  1. 安装
npm i vue-lazyload-next -S
  1. 使用
    main.ts
import VueLazyloadNext from 'vue-lazyload-next';

app.use(VueLazyloadNext, {
  // 添加一些配置参数 可不填
  
  // 懒加载默认加载图片
  loading: 'xxx.png',
  // 加载失败后加载的图片
  error: 'xxx.png',
  preLoad: 1.3, // 预加载高度的比例
  attempt: 3 // 尝试加载次数
});

这个插件支持背景图;且图片不会反复加载【加载过的不会再加载】;

方法2 IntersectionObserve()

API
原理
Intersection Observer是是浏览器原生提供的构造函数,使用它能省到大量的循环和判断。这个构造函数的作用是它能够观察可视窗口与目标元素产生的交叉区域。简单来说就是当用它观察我们的图片时,当图片出现或者消失在可视窗口,它都能知道并且会执行一个特殊的回调函数,就可以利用这个回调函数实现需要的操作。
hook
vue3中选择用hook进行集成
useLazyload.ts文件

// 定义自定义指令
const defineDirective = (app: any) => {
  app.directive('lazy', {
    mounted(el: HTMLImageElement, bindings: any) {
      // el表示使用指令的DOM元素
      // 指令的功能:实现图片的懒加载
      // 1、监听图片是否进入可视区
      const observer = new IntersectionObserver(([{ isIntersecting }]) => {
        // true;进入可视区域,false:未进入可视区域
        if (isIntersecting) {
          // 1、给图片的src属性赋值图片的地址
          el.src = bindings.value;
          // 2、取消图片的监听,默认是会一直监听的,如果不取消。就会一直执行
          // eslint-disable-next-line spellcheck/spell-checker
          observer.unobserve(el);
        }
      });
      // 监听dom元素
      observer.observe(el);
    }
  });
};
export default {
  install(app: any) {
    // 自定义指令
    defineDirective(app);
  }
};

基本用法
main.ts

import lazy from './hooks/useLazy';

app.use(lazy);

对需要进行懒加载的img标签,直接将:src替换为v-lazy

   <img
      class="image"
      :key="data.rendered_result_image_url"
      v-lazy="data.rendered_result_image_url"
    />

⚠️若图片为循环渲染、分页显示,则必须写key值,不然切换页面后页面视图不刷新

方法3 loading="lazy

HTML新增 loading属性
基本用法

<img src="xxx.png" loading="lazy">

loading 属性支持 3 种属性值:

  • auto 浏览器默认的懒加载策略,和不增加这个属性的表现一样
  • lazy 在资源距当前视窗到了特定距离内后再开始加载
  • eager 立即加载,无论资源在页面中什么位置

图片必须声明width和height,不然会看到布局发生移动
兼容性
在这里插入图片描述

不适用于背景图情况;

方法4 滚动监听+scrollTop+offsetTop+innerHeight

如何判断元素是否到达可视区域

  • window.innerHeight 是浏览器可视区的高度;
  • document.body.scrollTop || document.documentElement.scrollTop是浏览器滚动的过的距离;
  • imgs.offsetTop 是元素顶部距离文档顶部的高度(包括滚动条的距离);
  • 内容达到显示区域: img.offsetTop < window.innerHeight + document.body.scrollTop;
  • 到达可视区域后,imgs[i].src = imgs[i].getAttribute('data-src') as string; 将data-src属性值赋值给src,实现懒加载
    (在我项目中:)
    !!!!但在集成过程中发现,由于img父元素标签没有设置高度,scrollTop始终为0,无法实现动态计算window.innerHeight + document.body.scrollTop的值【一体化-算法版本-标准图】;不适用于没有设置父级高度的情况

方法5 滚动监听+getBoundingClientRect()

API

//获取所有img标签
const imgs = document.getElementsByTagName('img');

onMounted(() => {
   //用于首屏加载
  lazyLoad();
  //添加滚动事件监听
  document.addEventListener('scroll', throttle(lazyLoad, 500), true);
});
onUnMounted(() => {
  document.removeEventListener('scroll', throttle(lazyLoad, 500), true);
});

// 节流
const throttle = (fn: { apply: (arg0: any, arg1: any[]) => void }, t: number) => {
  let flag = true;
  const interval = t || 500;
  return function (this: any, ...args: any) {
    if (flag) {
      fn.apply(this, args);
      flag = false;
      setTimeout(() => {
        flag = true;
      }, interval);
    }
  };
};

const lazyLoad = () => {
  const offsetHeight = window.innerHeight || document.documentElement.clientHeight;
  Array.from(imgs).forEach(item => {
    const oBounding = item.getBoundingClientRect(); //返回一个矩形对象,包含上下左右的偏移值
    if (0 <= oBounding.top && oBounding.top <= offsetHeight) {
      //     //性能优化 进行判断 已经加载的不会再进行加载
      if (item.getAttribute('alt') !== 'loaded') {
        item.setAttribute('src', item.getAttribute('data-src') as string);
        item.setAttribute('alt', 'loaded');
      }
    }
  });
};

缺点

  • 挂载时需要立刻调用lazyLoad函数,不然首屏不会加载;若需要图片分页,切换分页后不会也主动加载,需要调用lazyLoad方法
  • 同样需要给图片设置key值,不然分页图片不刷新
  • 写在image组件内部的话会反复调用lazyload方法,需要写在外层组件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/78278.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

elementui 修改日期选择器el-date-picker样式

1. 案例&#xff1a; 2. css /* 最外层颜色 */ .el-popper.is-pure {background: url("/assets/imgList/memuBG.png") no-repeat;border: none;background-size:100% 100%}/* 日期 1.背景透明 */ .el-date-picker{background: transparent; }/* 日期 2.标题、左右图…

ThreadLocal(超详细介绍!!)

关于ThreadLocal&#xff0c;可能很多同学在学习Java的并发编程部分时&#xff0c;都有所耳闻&#xff0c;但是如果要仔细问ThreadLocal是个啥&#xff0c;我们可能也说不清楚&#xff0c;所以这篇博客旨在帮助大家了解ThreadLocal到底是个啥&#xff1f; 1.ThreadLocal是什么&…

Python爬虫性能优化:多进程协程提速实践指南

各位大佬们我又回来了&#xff0c;今天我们来聊聊如何通过多进程和协程来优化Python爬虫的性能&#xff0c;让我们的爬虫程序6到飞起&#xff01;我将会提供一些实用的解决方案&#xff0c;让你的爬虫速度提升到新的高度&#xff01; 1、多进程提速 首先&#xff0c;让我们来看…

【云原生】Docker基本原理及镜像管理

目录 一、Docker概述 1.1 IT架构的演进&#xff1a; 1.2 Docker初始 1.3 容器的特点 1.4 Docker容器与虚拟机的区别 1.5 容器在内核中支持2种重要技术 1.6 Docker核心概念 1&#xff09;镜像 2&#xff09;容器 3&#xff09;仓库 二、安装Docker 2.1 Yum安装Docker…

MySQL- sql语句基础

文章目录 1.select后对表进行修改&#xff08;delete&#xff09;2.函数GROUP_CONCAT()3.使用正则表达式 1.select后对表进行修改&#xff08;delete&#xff09; 报错&#xff1a;You can’t specify target table ‘Person’ for update in FROM clause 原因&#xff1a;mys…

由小波变换模极大值重建信号

给定信号&#xff0c; 令小波变换的尺度 则x(t)的二进小波变换为 令为取模极大值时的横坐标&#xff0c;那么就是模极大值。 目标是由坐标、模极大值及最后一级的低频分量重建信号x(t) 为了重建x(t)&#xff0c;假定有一信号集合h(t)&#xff0c;该集合中信号的小波变换和x(…

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) …

2022年12月 C/C++(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

第1题&#xff1a;数组逆序重放 将一个数组中的值按逆序重新存放。例如&#xff0c;原来的顺序为8,6,5,4,1。要求改为1,4,5,6,8。 输入 输入为两行&#xff1a;第一行数组中元素的个数n(1 输出 输出为一行&#xff1a;输出逆序后数组的整数&#xff0c;每两个整数之间用空格分隔…

升级STM32电机PID速度闭环编程:从F1到F4的移植技巧与实例解析

引言&#xff1a; 在嵌入式系统开发中&#xff0c;STM32系列微控制器广泛应用于各种应用领域。而对于直流有刷电机的控制&#xff0c;PID速度闭环是一种常用的控制方式。本文将以此为例&#xff0c;探讨如何从STM32F1系列移植到STM32F4系列&#xff0c;并详细介绍HAL库在不同型…

APSIM模型参数优化 批量模拟丨气象数据准备、物候发育和光合生产、物质分配与产量模拟、土壤水分平衡算法、土壤碳氮平衡模块、农田管理模块等

随着数字农业和智慧农业的发展&#xff0c;基于过程的农业生产系统模型在模拟作物对气候变化的响应与适应、农田管理优化、作物品种和株型筛选、农田固碳和温室气体排放等领域扮演着越来越重要的作用。APSIM (Agricultural Production Systems sIMulator)模型是世界知名的作物生…

分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测

分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测 目录 分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.分类预测 | MATLAB实现GAPSO-LSSVM多输入分类预测 2.代码说明&#xff1a;要求于Matlab 2021版及以上版本。 程序…

使用 Jython 在 Java 中运行 Python

文章目录 使用 Jython 在 Java 中运行 Python创建 Python 代码 安装 Jython 库将 Jython 库与 IDE 链接用 Java 编写 Python 代码并编译它用 Java 编译的用于添加两个数字的 Python 代码用 Java 编译的用于查找月份最后一天的 Python 代码一些用 Java 编译时不运行的 Python 库…

步入React正殿 - React组件设计模式

目录 扩展学习资料 高阶组件 /src/components/hoc/withTooltip.js /src/components/hoc/itemA.jsx /src/components/hoc/itemB.jsx /src/App.js 函数作为子组件【Render pprops】 函数作为子组件 /src/components/rp/itemC.jsx【父组件】 /src/components/rp/withToo…

Java版电子招投标管理系统源码-电子招投标认证服务平台-权威认证 tbms

​ 功能描述 1、门户管理&#xff1a;所有用户可在门户页面查看所有的公告信息及相关的通知信息。主要板块包含&#xff1a;招标公告、非招标公告、系统通知、政策法规。 2、立项管理&#xff1a;企业用户可对需要采购的项目进行立项申请&#xff0c;并提交审批&#xff0c;…

Java进阶篇--数据结构

目录 一.数组&#xff08;Array&#xff09;&#xff1a; 1.1 特点&#xff1a; 1.2 基本操作&#xff1a; 1.3 使用数组的好处包括&#xff1a; 1.4 数组也有一些限制&#xff1a; 二.集合框架&#xff08;Collections Framework&#xff09;&#xff1a; 2.1 列表…

【TA 挖坑02】RayMarching SDF 物体黏合

写在前面 由于实习和忙着论文很久没经营博客了&#xff0c;最近以各种方式收集到了一些想实现的效果&#xff0c;其中一个就是卡通云融合、变大变小、聚散收拢的效果如何实现的问题&#xff0c;这就不得不提搁置了很久的RayMarching... 挖坑&#xff01;整理一下有帮助的文章…

Octree八叉树python

原理 简单示例&#xff1a; 假设我们有以下一组三维点云数据&#xff1a; points [[0.1, 0.1, 0.1],[0.4, 0.1, 0.1],[0.1, 0.4, 0.1],[0.4, 0.4, 0.1],[0.1, 0.1, 0.4],[0.4, 0.1, 0.4],[0.1, 0.4, 0.4],[0.4, 0.4, 0.4], ] 我们可以使用八叉树将这些点云数据存储在三维空…

MATLAB高分辨率图片

把背景调黑&#xff0c;把曲线调黄&#xff0c;把grid调白&#xff0c;调调字体字号的操作 close all a0:0.1:10; noise2*rand(1,length(a)); bsin(a)sin(3*a)noise;plot(a,b,y,linewidth,2); ylim([-3 4]) %y轴范围 set(gca,xgrid,on,ygrid,on,gridlinestyle,-,Grid…

8.13黄金是否进入下行通道?下周开盘如何布局

近期有哪些消息面影响黄金走势&#xff1f;黄金多空该如何研判&#xff1f; ​黄金消息面解析&#xff1a;周五(8月11日)现货黄金小幅收低&#xff0c;受累于美元走强和美国国债收益率上升&#xff0c;本周录得6月底以来最差单周表现。投资者在评估最新一批通胀报告和消费者信…

【hive】简单介绍hive的几种join

文章目录 前言1. Common Join2. Map Join介绍&#xff1a;使用方法&#xff1a;限制&#xff1a; 3. Bucket Map Join介绍&#xff1a;好处&#xff1a;使用条件&#xff1a;使用方法&#xff1a; 4. Sort Merge Bucket Map Join介绍&#xff1a;如何使用&#xff1a; 5. Skew …