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

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

懒加载的原理为基于视口(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造成一定影响,但可以通过合理的策略来优化。例如,确保关键内容和链接在初始加载时即可被搜索引擎索引。

应用场景

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

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

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

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

相关文章

【JavaEE】Spring IoCDI详解

一.基本概念 1.Ioc基本概念 Ioc: Inversion of Control (控制反转), 也就是说 Spring 是⼀个"控制反转"的容器. 什么是控制反转呢? 也就是控制权反转. 什么的控制权发发了反转? 获得依赖对象的过程被反转了也就是说, 当需要某个对象时, 传统开发模式中需要自己通…

前端面试题日常练-day60 【面试题】

题目 希望这些选择题能够帮助您进行前端面试的准备&#xff0c;答案在文末 1. 在PHP中&#xff0c;以下哪个函数用于获取数组的长度&#xff1f; a) count() b) length() c) size() d) sizeof() 2. PHP中的预定义变量$_SESSION用于存储什么类型的数据&#xff1f; a) 用户…

美银美林:看好铜价涨到12000美元,这类铜矿企业弹性更大

美银美林指出&#xff0c;考虑到能源转型以及AI投资热潮对铜的需求巨大&#xff0c;到2026年铜供需缺口有望扩大一倍。给予紫金矿业、江西铜业等多家巨头买入评级&#xff0c;并认为一旦铜价上行&#xff0c;KGHM等规模较小、成本较高的企业的利润增长可能更为显著。 高盛、花…

小小万年历改头换面了

小小万年历改头换面了 ​ 前阶段编写了一个[万年历小程序][https://jl-zhenlaixiaowei.blog.csdn.net/article/details/139180401?spm=1001.2014.3001.5502],因为界面不太友好,所以这两天有空闲时间,我又对小工具进行了功能增加并改成了窗口界面,可以用鼠标点击和键盘输入…

python中while循环实现九九乘法表

i 1while i < 9: # 控制行的循环j 1while j < i: # 控制每行的输出print(f"{j}*{i}{j * i}\t", end"")j 1print()i 1运行截图&#xff1a;

餐饮淡季营销方案

餐饮淡季营销方案 时间: 2024-6-9 分类: 营销流量 作者: admin 0 次浏览 餐 饮 营 销 方 案 第一部分&#xff1a;餐饮淡季营销方案 第二部分&#xff1a;餐饮上半年营销方案 第一部分&#xff1a;餐饮淡季营销方案 春节过后&#xff0c;餐厅也将迎来一年中最漫长的经营淡季&a…

Cweek4+5

C语言学习 十.指针详解 6.有关函数指针的代码 代码1&#xff1a;(*(void (*)())0)(); void(*)()是函数指针类型&#xff0c;0是一个函数的地址 (void(*)())是强制转换 总的是调用0地址处的函数&#xff0c;传入参数为空 代码2&#xff1a;void (*signal(int, void(*)(int))…

ENSP校园网设计实验

前言 哈喽&#xff0c;我是ICT大龙。本次更新了使用ENSP仿真软件设计校园网实验。时间比较着急&#xff0c;可能会有错误&#xff0c;欢迎大家指出。 获取本次工程文件方式在文章结束部分。 拓扑设计 拓扑介绍---A校区 如图&#xff0c;XYZ大学校园网设计分为3部分&#xff0…

JDK下载安装Java SDK

Android中国开发者官网 Android官网 (VPN翻墙) 方案1&#xff1a;通过brew命令 下载OracleJDK(推荐) brew --version //是否已存在homebrew环境 brew install --cask oracle-jdk //通过brew命令直接下载并安装OracleJDK(VPN、登录密码) java -version //验证JDK是否下载并安装…

裸机程序设计模式

裸机程序的设计模式可以分为&#xff1a;轮询、前后台、定时器驱动、基于状态机。前面三种方法都无法解决一个问题&#xff1a;假设有A、B两个都很耗时的函数&#xff0c;无法降低他们互相之间的影响。第4中方法可以解决这个问题&#xff0c;但是实践起来有难度。 1、轮询模式…

UI学习的案例——照片墙

照片墙案例 在实现照片墙案例之前先讲一下userInteractionEnable这个属性。 首先这个属性属于UIView&#xff0c;这个属性是bool类型&#xff0c;如果为YES的话&#xff0c;这个UIView会接受有关touch和keyboard的相关操作&#xff0c;然后UIView就可以通过相应的一些方法来处…

启动xv6遇坑记录

我是在VMware上的Ubuntu22.04.4搭建的&#xff0c;启动xv6遇到超多bug&#xff0c;搞了好几天&#xff0c;所以记录一下。 目录 git push的时候报错 make qemu缺少包 运行make qemu时卡住 可能有影响的主机设置 git push的时候报错 remote: Support for password authent…

TMS320F280049学习3:烧录

TMS320F280049学习3&#xff1a;烧录 文章目录 TMS320F280049学习3&#xff1a;烧录前言一、烧录RAM二、烧录FLASH总结 前言 DSP的烧录分为两种&#xff0c;一种是将程序烧录到RAM中&#xff0c;一种是烧录到FLASH中&#xff0c;烧录ARM中的程序&#xff0c;只要未掉电&#x…

SpringBoot中@Scheduled注解默认单线程,改为多线程线程池

Spring Boot提供的Scheduled注解默认是以单线程方式执行。 1.配置类 Configuration public class ScheduleConfig implements SchedulingConfigurer {/** 定时任务线程池个数改为多线程。默认为单线程 */Overridepublic void configureTasks(ScheduledTaskRegistrar taskRegi…

黑马集成电路应用开发入门课程

"黑马集成电路应用开发入门课程"旨在引导学员了解集成电路应用开发的基础知识和技能。课程内容涵盖集成电路原理、设计流程、应用开发工具等&#xff0c;通过实践项目和案例分析&#xff0c;帮助学员掌握集成电路应用开发的核心概念和方法&#xff0c;为未来在该领域…

轻松上手MYSQL:SQL优化之Explain详解

​​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 文章目录 一、Explain1.1 explain作用1.2 explain列说明idselect_typetableparti…

React antd 怎么封装权限按钮

在 React 中使用 Ant Design(antd)封装一个权限按钮通常涉及到两个主要部分:按钮的渲染逻辑和权限的验证。以下是一个基本的步骤和示例代码,展示如何封装一个权限按钮: 步骤 定义权限:首先,你需要定义应用中的权限。这些权限可能是一个简单的字符串数组,或者是更复杂的…

6.9总结(省赛排位赛1)

省赛排位赛1省赛排名赛1 - Virtual Judge (vjudge.net) 思路&#xff1a; 其实就是一个斐波拉契数列&#xff0c;当前项前两项之和&#xff0c;先将范围内的数全部存起来放进一个数组&#xff0c;再进行累加查询 代码&#xff1a; #define _CRT_SECURE_NO_WARNINGS 1 #incl…

Nginx替代软件

Nginx 是一款广受欢迎的高性能 Web 服务器&#xff0c;以其事件驱动的架构和轻量级的特点而闻名。尽管 Nginx 非常强大&#xff0c;但确实存在一些替代品&#xff0c;它们各自具有独特的优点。以下是一些 Nginx 的替代软件及其优点&#xff1a; 1. LiteSpeed - LiteSpeed 是…

将单条十六进制字符串转换为单个 pcap 文件

第一步&#xff1a;将字符串转换为 hex 格式文件 echo 01005e00000ac20173fe0000080045c0003c000000000258cd9f0a000001e000000a0205ee68000000000000000000000000000000640001000c010001000000000f000400080c040102 | xxd -r -p | od -Ax -tx1 > icmp.pcap 第二步&#x…