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-checkerobserver.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

   <imgclass="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方法,需要写在外层组件

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Appium Desktop安装

【提示&#xff1a;官方已不再维护&#xff0c;建议命令行方式安装&#xff0c;但可以学习了解一下】 Appium Desktop是一款适用于Mac、Windows和Linux的应用程序&#xff0c;它以漂亮灵活的UI为您提供Appium自动化服务器的强大功能。它基本上是Appium Server的图形界面。您可…

Day8 智慧商城

项目演示 项目收获 创建项目 调整初始化目录 1.删components里的所有文件 2.删views里的所有文件 3.router/index.js 删路由 删规则 import Vue from vue import VueRouter from vue-routerVue.use(VueRouter)const router new VueRouter({routes: [] })export default route…

【Git】本地搭建Gitee、Github环境

本地 &#xff08;Local&#xff09; 1、使用命令生成公钥&#xff08;pub文件&#xff09; 1. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "github_id_rsa" 2. $ ssh-keygen -t rsa -C "xxxxxxxemail.com" -f "gitee_id_rsa" …

Rides分布式缓存

分布式缓存 -- 基于Redis集群解决单机Redis存在的问题 单机的Redis存在四大问题&#xff1a; 1.Redis持久化 Redis有两种持久化方案&#xff1a; RDB持久化 AOF持久化 1.1.RDB持久化 RDB全称Redis Database Backup file&#xff08;Redis数据备份文件&#xff09;&#x…

Flink 流式读写文件、文件夹

文章目录 一、flink 流式读取文件夹、文件二、flink 写入文件系统——StreamFileSink三、查看完整代码 一、flink 流式读取文件夹、文件 Apache Flink针对文件系统实现了一个可重置的source连接器&#xff0c;将文件看作流来读取数据。如下面的例子所示&#xff1a; StreamExe…

Java后端开发面试题——框架篇

Spring框架中的bean是单例的吗&#xff1f;Spring框架中的单例bean是线程安全的吗&#xff1f; singleton : bean在每个Spring IOC容器中只有一个实例。 prototype&#xff1a;一个bean的定义可以有多个实例。 Spring bean并没有可变的状态(比如Service类和DAO类)&#xff0c…

使用kubeadm工具升级kubernetes

一、背景&#xff1a; kubeadm部署的kubernetes集群进行升级&#xff0c;通常先升级控制节点&#xff0c;控制节点升级完成后再升级工作节点&#xff0c;本博文只升级了控制节点&#xff0c;工作节点按照相同的流程进行升级即可 环境说明&#xff1a; 主机名节点11.0.1.200k8s…

PyTorch DataLoader 报错 “DataLoader worker exited unexpectedly“ 的解决方案

注意&#xff1a;博主没有重写d2l的源代码文件&#xff0c;而是创建了一个新的python文件&#xff0c;并重写了该方法。 一、代码运行日志 C:\Users\Administrator\anaconda3\envs\limu\python.exe G:/PyCharmProjects/limu-d2l/ch03/softmax_regression.py Traceback (most r…

Ohio主题 - 创意组合和代理机构WordPress主题

Ohio主题是一个精心制作的多用途、简约、华丽、多功能的组合和创意展示主题&#xff0c;具有敏锐的用户体验&#xff0c;您需要构建一个现代且实用的网站&#xff0c;并开始销售您的产品和服务。它配备了最流行的WordPress页面构建器 WPBakery Page Builder&#xff08;以前称为…

avue多选列表根据后端返回的某个值去判断是否选中;avue-curd多选回显

效果如上&#xff1a; getSiteList().then(res > {//列表数据this.siteData res.data.datathis.$nextTick(()>{this.siteData.forEach(item>{//业务条件if(item.configid&&item.configid!0&&item.configid>0){//符合条件时调用选中的方法this.$…

OC调用Swift编写的framework

一、前言 随着swift趋向稳定&#xff0c;越来越多的公司都开始用swift来编写苹果相关的业务了&#xff0c;关于swift的利弊这里就不多说了。这里详细介绍OC调用swift编写的framework库的步骤 二、制作framework 1、新建项目&#xff0c;选择framework 2、填写framework的名称…

损失函数,基于概率分布度量的损失函数,信息量,信息熵的作用

目录 损失函数中为什么要用Log&#xff1a;概率损失函数-乘法转加法-便于求偏导 信息量&#xff0c;信息熵的作用 信息的作用是消除不确定性&#xff1a;信息量是0&#xff0c;事件确定 回答只是Y,N&#xff0c;因此对数底数为2​编辑 一句话描述的事件发生的概率越低&#…

隔断让你的办公室变得更加智能、环保、人性化

隔断可以在办公室中起到多种重要作用&#xff0c;使办公室更加智能、环保和人性化。以下是一些可能的方式&#xff1a; 1. 智能办公室控制系统&#xff1a;可以通过隔断集成智能办公室控制系统&#xff0c;实现办公室照明、温度和空调等设备的自动调节&#xff0c;提高能效和舒…

以 Java NIO 的角度理解 Netty

文章目录 前言Java NIO 工作原理Selector 的创建ServerSocketChannel 的创建ServerSocketChannel 注册 Selector对事件的处理总结 前言 上篇文章《Netty 入门指南》主要涵盖了 Netty 的入门知识&#xff0c;包括 Netty 的发展历程、核心功能与组件&#xff0c;并且通过实例演示…

用户信任建立:银行卡三要素API的隐私保护与数据安全

引言 在数字支付和金融领域&#xff0c;用户信任是构建稳健金融生态的关键。随着金融科技的迅速发展&#xff0c;银行卡三要素API作为一种用于身份验证和支付安全的工具&#xff0c;不仅带来了便利&#xff0c;也引发了对隐私保护和数据安全的关切。本文将探讨银行卡三要素API…

C语言编写图形界面

文章目录 环境使用库基础概念句柄 程序的入口创建窗口定义窗口类注册窗口类创建窗口 完整代码运行效果 环境 使用的是VSCode MinGW&#xff1b; 使用库 我们使用windows.h库来实现图形化界面。 头文件如下&#xff1a; #include <windows.h>windows.h是 Windows 操作…

Redis中的分布式锁及其延生的问题

前言 本文将着重介绍Redis中的分布式锁及其与出现的死锁和锁误删问题 什么是分布式锁 首先问题就是什么是分布式锁&#xff0c;分布式锁就是分布式系统中实现并发控制的一种锁机制&#xff0c;它可以保证多个节点在同一个时间只有有一个能成功竞争到系统资源&#xff08;共享…

微软Win11 Dev预览版Build23526发布

近日&#xff0c;微软Win11 Dev预览版Build23526发布&#xff0c;修复了不少问题。牛比如斯Microsoft&#xff0c;也有这么多bug&#xff0c;所以你写再多bug也不作为奇啊。 主要更新问题 [开始菜单&#xff3d; 修复了在高对比度主题下&#xff0c;打开开始菜单中的“所有应…

【LeetCode-中等题】128. 最长连续序列

题目 题解一&#xff1a;HeshSet枚举 思路&#xff1a;先对数组进行set去重&#xff0c;核心就是&#xff0c;先找出临界值&#xff08;假设以最小临界为例&#xff0c;那么这个临界值自己就是最小值&#xff0c;&#xff09;&#xff0c;以临界值不断做加1操作&#xff0c;看…

使用拦截器+Redis实现接口幂等

文章目录 使用拦截器Redis实现接口幂等1.思路分析2.具体实现2.1 创建redis工具类2.2 自定义幂等注解2.2 自定义幂等拦截器2.3 注入拦截器到容器 3.测试 使用拦截器Redis实现接口幂等 1.思路分析 接口幂等有很多种实现方式&#xff0c;拦截器/AOPRedis&#xff0c;拦截器/AOP本…