当前位置: 首页 > news >正文

面试官:前端实现图片懒加载怎么做?这不是撞我怀里了嘛!

前端懒加载(也称为延迟加载或按需加载)是一种网页性能优化的技术,主要用于在网页中延迟加载某些资源,如图片、视频或其他媒体文件,直到它们实际需要被用户查看或交互时才进行加载。这种技术特别适用于长页面或包含大量媒体资源的页面,因为它可以显著提高页面加载速度,减少用户等待时间,并降低服务器负载。

懒加载的原理为基于视口(viewport)的概念,即用户当前在屏幕上可见的区域。当页面加载时,只有视口内的资源会被立即加载,而视口外的资源则会被延迟加载。当用户滚动页面或触发其他交互行为时,视口外的资源才会根据需要被加载。

懒加载的优点:

  • 提高页面加载速度:由于只加载视口内的资源,页面初始加载时间大大减少。
  • 节省带宽和服务器资源:减少不必要的资源加载,降低服务器负载和带宽消耗。
  • 提升用户体验:减少用户等待时间,使页面更加流畅和响应迅速。

那么实现懒加载的方式有哪些呢?本文主要从原生、vue、react角度来说一下实现懒加载的常见方法!

一、原生的loading属性

loading 属性指定浏览器是应立即加载图像还是延迟加载图像。现代浏览器已经开始支持img标签的loading属性。设置 loading=“lazy” 只有鼠标滚动到该图片所在位置才会显示。

loading的属性值有eager和lazy,默认值为eager,表示图像立即加载;lazy表示图像延迟加载,只有鼠标滚动到该图片所在位置才会显示。

<img src="/images/paris.jpeg" alt="Paris" loading="lazy">
<img src="/images/nature.jpeg" alt="Nature" loading="lazy">

这是实现懒加载最简单的方法,无需额外的JavaScript代码。

二、Intersection Observer API

Intersection Observer API(交叉观察器 API)提供了一种异步检测目标元素与祖先元素或顶级文档的视口相交情况变化的方法。

过去,要检测一个元素是否可见或者两个元素是否相交并不容易,很多解决办法不可靠或性能很差。然而,随着互联网的发展,这种需求却与日俱增,比如,在页面滚动时“懒加载”图像或其他内容这些情况都需要用到相交检测。

const io = new IntersectionObserver(callback, option);

IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(该参数可选)。

构造函数的返回值是一个观察器实例。实例的observe方法可以指定观察哪个 DOM 节点。

// 开始观察
io.observe(document.getElementById('example'));// 停止观察
io.unobserve(element);// 关闭观察器
io.disconnect();

上面代码中,observe的参数是一个 DOM 节点对象。如果要观察多个节点,就要多次调用这个方法。

io.observe(elementA);
io.observe(elementB);

**callack参数:**目标元素的可见性变化时,就会调用观察器的回调函数callback。

一般会触发两次:(1)目标元素刚刚进入视口(开始可见);(2)完全离开视口(开始不可见)。

callback函数的参数是一个数组,每个成员都是一个IntersectionObserverEntry对象。

**IntersectionObserverEntry 对象:**提供目标元素的信息,一共有六个属性。

  • time:可见性发生变化的时间,是一个高精度时间戳,单位为毫秒。
  • target:被观察的目标元素,是一个 DOM 节点对象。
  • rootBounds:根元素的矩形区域的信息,getBoundingClientRect()方法的返回值,如果没有根元素(即直接相对于视口滚动),则返回null。
  • boundingClientRect:目标元素的矩形区域的信息。
  • isIntersecting: 布尔值,目标元素与交集观察者的根节点是否相交(常用)。
  • intersectionRect:目标元素与视口(或根元素)的交叉区域的信息。
  • intersectionRatio:目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0。

所以可以通过判断isIntersecting属性是否为true来判断元素的可见性。

对于需要懒加载的图片,使用data-src代替src。

<img data-src="image.jpg" alt="description">
document.addEventListener("DOMContentLoaded", function() {const images = document.querySelectorAll('img[data-src]');const loadImage = function(image) {image.setAttribute('src', image.getAttribute('data-src'));image.onload = function() {image.removeAttribute('data-src');}}//使用IntersectionObserver监听元素是否进入可视区域if ('IntersectionObserver' in window) {var observer = new IntersectionObserver(function(items, observer) {items.forEach(function(item) {if (item.isIntersecting) {loadImage(item.target);observer.unobserve(item.target);}});}, {threshold: 0.01});images.forEach(function(img) {observer.observe(img);});} else {//不支持IntersectionObserver,直接加载所有图片images.forEach(function(img) {loadImage(img);});}
});

四、事件监听+getBoundingClientReact()

旧版本的浏览器可能不支持Intersection ObserverAPI,此时可以用 getBoundingClientRect 和事件监听结合来实现。

Element.getBoundingClientRect() 方法返回一个 DOMRect 对象,其提供了元素的大小及其相对于视口的位置。

返回值是一个 DOMRect 对象,是包含整个元素的最小矩形(包括 padding 和 border-width)。该对象使用 left、top、right、bottom、x、y、width 和 height 这几个以像素为单位的只读属性描述整个矩形的位置和大小。除了 width 和 height 以外的属性是相对于视图窗口的左上角来计算的。

在这里插入图片描述

const rectObject = object.getBoundingClientRect()

因此,当rectObject.top的值处于0-视口高度,则元素处于可视区。即

getBoundingClientRect(ele).top >= 0 && getBoundingClientRect(ele).top <= offsetHeight

实现如下:

function isElementInviewport(el) {const rect = el.getBoundingClientRect();return (rect.bottom >= 0 &&rect.right >= 0 &&rect.top <= (window.innerHeight || document.documentElement.clientHeight) && rect.left <= (window.innerwidth || document.documentElement.clientWidth);)
}function checkLazyLoad() {const lazyImages = Array.prototype.slice.call(document.querySelectorAll('img[data-src]'));lazyImages.forEach(function(img) {if (isElementInViewport(img)) {img.src = img.getAttribute('data-src');img.removeAttribute('data-src');}});if (lazyImages.length === 0) { //如果所有懒加载图片都已加载,移除滚动监听window.removeEventListener('scroll', checkLazyLoad);window.removeEventListener('resize', checkLazyLoad);}
}//监听事件
window.addEventListener('scroll', checkLazyLoad);
window.addEventListener('resize', checkLazyLoad);
window.addEventListener('DOMContentLoaded', checkLazyLoad);

五、使用第三方库

许多第三方库可以实现懒加载,例如lazysizes 和lozad.js。

以下是使用 lazysizes 库的示例:

首先,你需要引入lazysizes 库。

<script src="lazysizes.min.js" async=""></script>

然后修改你的标签,增加lazyload 类和data-src 属性来取代 src即可。

<img data-src="image.jpg" class="lazyload" alt="image" />

Iazysizes 库会自动处理剩下的工作。

六、vue中使用vue-lazyload

在Vue中vue-lazyload插件用的比较多。

首先,安装vue-lazyload:

npm install vue-lazyload--save

接着在你的Vue项目中引入并使用vue-lazyload:

// main.js
import Vue from 'vue'
import App from './App.vue'
import VueLazyload from 'vue-lazyload'
Vue.use(VueLazyload)

//或者添加选项,例如加载时的占位图或加载失败时的图像

Vue.use(VueLazyload, {preLoad: 1.3,error: 'error.png',loading: 'loading.gif',attempt: 1
})
new Vue({render: h => h(App)
}).$mount('#app')

然后在组件中使用v-lazy指令来替换src属性:

<img v-lazy="imgUrl" alt="image">

七、React中的lazy函数

React项目中,你可以使用React自带的lazy函数结合Suspense组件来实现图片懒加载。

React.lazy目前仅支持默认导出(default exports)如果要加载的组件使用了命名导出,你需要一个中间模块来重新导出它为默认模块。

首先,你需要创建一个懒加载组件来包装图片:

// LazyImage.jsx
import React from'react';
const LazyImage = ({ src, alt }) => {return(<img src={src} alt={alt} />);
};
export default LazyImage;

然后使用React.lazy来动态导入这个组件:

// App.js 或者其他父组件
import React, { Suspense } from 'react';
const LazyImage = React.lazy(() => import('./LazyImage'));
// 懒加载组件
const App = () =>{return (<div><Suspense fallback={<div>Loading...</div>}>{/* 在Suspense组件中渲染懒加载的组件 */}<LazyImage src="image.jpg" alt="图片描述"/></Suspense></div>);
};
export default App;

Suspense 组件允许你在等待加载时显示一个加载指示器(例如上面的

Loading…
)。

总结

注意事项

  • 兼容性:不同的浏览器和设备对懒加载的支持程度不同,需要确保所选用的懒加载方案具有良好的兼容性。
  • 用户体验:懒加载不应该影响用户的正常浏览和操作。例如,在图片加载过程中,可以显示占位符或加载提示,以增加用户的等待体验。
  • SEO优化:虽然懒加载可能会对SEO造成一定影响,但可以通过合理的策略来优化。例如,确保关键内容和链接在初始加载时即可被搜索引擎索引。

应用场景

  • 长页面和图片密集型网站:如新闻网站、社交媒体、电商网站等,这些网站通常包含大量的图片和长页面,采用懒加载可以显著提高页面性能和用户体验。
  • 视频和音频资源丰富的网站:如视频分享网站、音乐平台等,这些网站的视频和音频资源占用大量带宽和服务器资源,采用懒加载可以有效降低服务器负载和带宽消耗。
  • 移动设备优化:移动设备的网络环境通常较差,采用懒加载可以减少用户的流量消耗和等待时间,提升用户体验。

总之,懒加载技术广泛应用于各类网站和应用中,特别是长页面、图片密集的网站、电商网站、新闻网站等。在这些场景中,懒加载技术可以显著提高页面性能和用户体验。

相关文章:

面试官:前端实现图片懒加载怎么做?这不是撞我怀里了嘛!

前端懒加载&#xff08;也称为延迟加载或按需加载&#xff09;是一种网页性能优化的技术&#xff0c;主要用于在网页中延迟加载某些资源&#xff0c;如图片、视频或其他媒体文件&#xff0c;直到它们实际需要被用户查看或交互时才进行加载。这种技术特别适用于长页面或包含大量…...

每天学习一个Windows命令或Linux命令——seq

今天我们来学习 seq命令&#xff01; seq命令&#xff08;单词sequence序列的缩写&#xff09;是Linux系统中用于输出序列化的一串整数的命令。 一、seq用法 seq用法一共有以下三种&#xff1a; seq [选项]... 尾数 seq [选项]... 首数 尾数 seq [选项]... 首数 增量&#…...

C++设计模式-中介者模式,游戏对象之间的碰撞检测

运行在VS2022&#xff0c;x86&#xff0c;Debug下。 31. 中介者模式 中介者模式允许对象之间通过一个中介者对象进行交互&#xff0c;而不是直接相互引用。可以减少对象之间的直接耦合&#xff0c;同时集中化管理复杂的交互。应用&#xff1a;如在游戏开发中&#xff0c;可以使…...

Rust-02-变量与可变性

在Rust中&#xff0c;变量和可变性是两个重要的概念。 变量&#xff1a;变量是用于存储数据的标识符。在Rust中&#xff0c;变量需要声明其类型&#xff0c;例如&#xff1a; let x: i32 5; // 声明一个名为x的变量&#xff0c;类型为i32&#xff08;整数&#xff09;&#…...

mov指令中不允许的操作——汇编语言

在 x86 汇编语言中&#xff0c;MOV 指令的限制有助于确保系统的稳定性和正确的操作。下面详细解释为什么这些操作是不允许的。 1. 段寄存器之间直接传送数据 MOV DS, ES ; 错误&#xff0c;不允许原因&#xff1a; 段寄存器是用来定义程序段的开始位置&#xff0c;如代码段…...

Python进阶-部署Flask项目(以TensorFlow图像识别项目WSGI方式启动为例)

本文详细介绍了如何通过WSGI方式部署一个基于TensorFlow图像识别的Flask项目。首先简要介绍了Flask框架的基本概念及其特点&#xff0c;其次详细阐述了Flask项目的部署流程&#xff0c;涵盖了服务器环境配置、Flask应用的创建与测试、WSGI服务器的安装与配置等内容。本文旨在帮…...

WooYun-2016-199433 -phpmyadmin-反序列化RCE-getshell

参考资料&#xff1a; Phpmyadmin 脚本/设置.php反序列化漏洞 &#xff08;WooYun-2016-199433&#xff09;复现_phpmyadmin scriptssetup.php 反序列化漏洞-CSDN博客 https://blog.csdn.net/haoxue__/article/details/129368455利用pearcmd.php文件包含拿shell&#xff08;L…...

社交“学习伙伴”:Meta Llama助力对话升级

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…...

LabVIEW 反向工程的实现与法律地位

什么是LabVIEW反向工程&#xff1f; 反向工程是指从现有的应用程序或软件中推导出其设计、架构、代码等信息的过程。对于LabVIEW而言&#xff0c;反向工程涉及从现有的VI&#xff08;虚拟仪器&#xff09;文件、项目或应用程序中提取出设计思路、功能模块、算法实现等。 LabV…...

Python怎么做单元测试

在Python中&#xff0c;最常用的单元测试框架是unittest。以下是如何使用unittest进行单元测试的步骤&#xff1a; 导入unittest模块&#xff1a; 首先&#xff0c;你需要导入unittest模块。 import unittest创建测试类&#xff1a; 你需要创建一个继承自unittest.TestCase的类…...

ghidra

https://github.com/NationalSecurityAgency/ghidra ghidra是一个so的逆向工具&#xff0c;功能和jadx-gui类似&#xff0c;但是和jadx-gui专注于java层的不同&#xff0c;ghidra专注于native层的代码反编译&#xff08;从二进制到c语言&#xff09;。 一、 安装 准备好java1…...

如何解决网络问题?

组织和 IT 管理员尽其所能完善他们的网络&#xff0c;但是&#xff0c;不同程度的网络问题仍然可能出现&#xff0c;这些网络问题需要立即响应和解决&#xff0c;如果这些问题在不合理的时间内得不到解决&#xff0c;网络和组织的损害可能会付出高昂的代价。这就是为什么 IT 管…...

高速USB转串口芯片CH343

CH343封装 截止目前&#xff0c;主要封装有 SOP16: CH343G QFN16: CH343P ESSOP10: CH343K,截止24年6月未生产 CH343串口速度 最高串口速度&#xff1a; 6Mbps,比CH340的2M&#xff0c;快3倍 1、概述 参考版本&#xff1a;1E CH343 是一个 USB 总线的转接芯片&#xff0c;…...

C++ MPI多进程并发

下载 用法 mpiexec -n 8 $PROCESS_COUNT x64\Debug\$TARGET.exe 多进程并发启动 mpiexec -f hosts.txt -n 3 $PROCESS_COUNT x64\Debug\$TARGET.exe 联机并发进程&#xff0c;其它联机电脑需在相同路径下有所有程序 //hosts.txt 192.168.86.16 192.168.86.123 192.168…...

UFS协议入门-分层结构

写在前面:本文参考UFS jedec3.1,本文思维导图如下 1. 分层概述 UFS协议分为3层,从上至下分别是:应用层(UAP),传输层(UTP),互联层(UIC),具体结构如下图所示。 2.1 应用层 在应用层(UAP)中,包括:UFS指令集(UCS),设备管理器(Device Manager),任务管理器(Task Manager…...

Docker Desktop - WSL distro terminated abruptly

打开 PowerShell 或以管理员身份运行的命令提示符。运行以下命令以列出已安装的 WSL 分发&#xff1a; wsl --list 运行以下命令以注销 Docker 相关的分发 wsl --unregister <distro_name> 将<distro_name>替换为实际的 Docker 相关分发的名称。将<distro_…...

HTML-CSS练习例子

HTML CSS 练习 https://icodethis.com 作为前端练习生。不敲代码只看&#xff0c;入门是很慢的&#xff0c;所以直接实战是学习前端最快的途径之一。 这个网站练习HTML CSS的&#xff0c;可以打开了解一下&#xff0c;可以每天打卡&#xff0c;例子简单&#xff0c;循序渐进&…...

【JavaScript脚本宇宙】创造声音的魔法:深入了解Web音频处理库

聆听创意可能性&#xff1a;解锁Web音频库的神奇功能 前言 在Web开发中&#xff0c;处理音频是一个重要且常见的需求。许多JavaScript库和框架旨在简化音频处理和交互式音乐的创建过程。本文将探讨几个流行的Web音频库&#xff0c;介绍它们的概述、主要特性、使用示例以及适用…...

苹果需要专注于让人工智能变得实用,而不是华而不实

谷歌和微软已将其开发者大会作为展示其生成式人工智能能力的平台&#xff0c;现在所有人的目光都集中在下周的全球开发者大会上&#xff0c;预计Apple Intelligence将在此首次亮相。 这家总部位于库比蒂诺的公司面临着巨大的压力。 苹果在人工智能竞赛中落后于同行&#xff0…...

安全专业的硬件远控方案 设备无网也能远程运维

在很多行业中&#xff0c;企业的运维工作不仅仅局限在可以联网的IT设备&#xff0c;不能连接外网的特种设备也需要专业的远程运维手段。 这种特种设备在能源、医疗等行业尤其常见&#xff0c;那么我们究竟如何通过远程控制&#xff0c;对这些无网设备实施远程运维&#xff0c;…...

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

变量 varablie 声明- Rust 变量 let mut 声明与 C/C++ 变量声明对比分析

一、变量声明设计&#xff1a;let 与 mut 的哲学解析 Rust 采用 let 声明变量并通过 mut 显式标记可变性&#xff0c;这种设计体现了语言的核心哲学。以下是深度解析&#xff1a; 1.1 设计理念剖析 安全优先原则&#xff1a;默认不可变强制开发者明确声明意图 let x 5; …...

【Java学习笔记】Arrays类

Arrays 类 1. 导入包&#xff1a;import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序&#xff08;自然排序和定制排序&#xff09;Arrays.binarySearch()通过二分搜索法进行查找&#xff08;前提&#xff1a;数组是…...

(二)TensorRT-LLM | 模型导出(v0.20.0rc3)

0. 概述 上一节 对安装和使用有个基本介绍。根据这个 issue 的描述&#xff0c;后续 TensorRT-LLM 团队可能更专注于更新和维护 pytorch backend。但 tensorrt backend 作为先前一直开发的工作&#xff0c;其中包含了大量可以学习的地方。本文主要看看它导出模型的部分&#x…...

页面渲染流程与性能优化

页面渲染流程与性能优化详解&#xff08;完整版&#xff09; 一、现代浏览器渲染流程&#xff08;详细说明&#xff09; 1. 构建DOM树 浏览器接收到HTML文档后&#xff0c;会逐步解析并构建DOM&#xff08;Document Object Model&#xff09;树。具体过程如下&#xff1a; (…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

如何应对敏捷转型中的团队阻力

应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中&#xff0c;明确沟通敏捷转型目的尤为关键&#xff0c;团队成员只有清晰理解转型背后的原因和利益&#xff0c;才能降低对变化的…...