百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

使用Vue.js指令和IntersectionObserver优化图像加载

bigegpt 2024-10-17 08:07 11 浏览

当我考虑性能以及如何加载网站时,我首先想到的是,当加载内容时,页面上显示的最后一个元素是图像。

今天的图像(它们在单页上的大小和数量)在性能方面可能是一个主要问题。请记住,网站的页面加载对转换率有直接影响,不应忽略此问题。

在本文中,我想描述一种减少网站初始权重的方法。我将演示的是,当他/她看到初始视图时,如何仅加载用户可见的内容,并且仅在需要时延迟加载所有其他重量级元素(如图像)。

要做到这一点,我们需要解决两件事:

  1. 如何存储我们想要加载的图像的源,而不是首先加载它。
  2. 如何检测图像何时变为可见(需要)给用户并触发加载图像的请求。

我们将使用数据属性,IntersectionObserver和Vue.js自定义指令解决上述问题。

为了便于理解,我创建了一个示例,一个随机文章列表,每个文章都包含一个简短的描述,图像和指向文章来源的链接。我们将通过组件的创建过程来显示文章列表,显示单个文章以及显示(和延迟加载)特定文章的图像。

我想要展示的大部分内容都基于显示图像的组件,因此我将展示该组件的外观基本示例。我们将在接下来的部分中逐步解释,所以不要在代码中过深。

ImageItem.vue

在组件中,我们有一个ImageSpinner组件,它在加载图像时显示,一个img标签负责保持图像源并在加载完成时显示图像。

LazyLoadDirective通过添加v-lazyload属性将关键延迟加载逻辑提取到在我们的组件上使用的逻辑。

ImageItem.vue

该组件的脚本部分如下所示:

ImageItem.vue

如上所述,延迟加载逻辑保存在一个指令中LazyLoadDirective:

LazyLoadDirective.js

这只是一个工作示例的一部分,您可以在此Codesandbox示例中找到整个示例。我们将逐个分析代码,并在下一节中查看实际发生的情况。

真实示例:创建LazyLoadDirective并在ImageItem组件中使用它

1.创建一个基本的ImageItem组件

让我们从创建一个显示图像的组件开始(不涉及延迟加载)。在模板中,我们创建一个包含图像的图形标记,图像本身接收带有图像源(url)的src属性。

ImageItem.vue

在脚本部分,我们收到了prop source,它为我们显示的图像提供了源URL。

ImageItem.vue

这很好,我们渲染我们想要的图像,但如果我们保持原样,我们将立即加载图像,而无需等待组件在我们的屏幕上可见。这不是我们想要的,所以让我们进入下一步。

2.防止在创建组件时加载图像。

为了防止图像被加载,我们需要从img标签中删除src属性。但正如一开始所指出的那样,我们仍然需要将图像源保留在某处。保存该信息的好地方是data- *属性。

根据其定义data- *属性允许我们存储有关标准语义HTML元素的信息。

听起来非常适合我们的需求。

ImageItem.vue

好的,完成后我们将不会加载我们的图像。但是等等,我们不会加载我们的形象......永远!

显然这不是我们想要的,我们想在特定条件下加载我们的图像。我们可以通过将src属性替换为保留的图像源URL来请求加载图像data-url。这是容易的部分,我们现在遇到的问题是 - 什么时候应该更换src?

我们希望在携带它的组件对用户可见时加载图像。我们如何检测用户是否看到我们的图像?让我们在下一步检查出来。

3.检测图像何时对用户可见。

如果你遇到过这个挑战,你可能最终会使用一些疯狂的魔法javascript,当你完成后看起来不是很好。

例如,我们可以使用事件和事件处理程序来检测滚动位置,偏移值,元素高度和视口高度,并计算图像是否在视口中。它甚至听起来很疯狂,不是吗?

如果我们确实需要,我们可能会坚持这个解决方案(无论多么丑陋),但这样做对我们的表现有直接的影响。每次有滚动事件时都会执行这些计算。更糟糕的是,想象一下,如果在每个滚动事件中可见或不可见,每个必须重新计算的几十个图像。

这太疯狂了!

4. 交叉观察员救援!

检测元素在视口中是否可见的这种非常低效的方法可以通过使用Intersection Observer API来解决。

查看定义,它允许您配置一个被调用的回调,只要一个元素(称为目标)与设备视口或指定元素相交。

当元素在视口中可见时触发自定义回调函数?听起来像是我们需要的魔法咒语。

那么,我们需要做些什么呢?

要使用Intersection Observer,我们需要做一些事情:

  • 创建一个新的交叉点观察者
  • 观察我们希望延迟加载的元素以进行可见性更改
  • 当元素在视口中时,加载元素(替换src为我们的data-url)
  • 元素加载后,停止观察它的可见性变化(unobserve)

Vue中,我们可以使用自定义指令来包装所有这些功能,然后在需要时重用它。

5.创建自定义Vue指令

什么是自定义指令?根据文档,它是一种在元素上获得低级DOM访问的方法。例如,更改特定DOM元素的属性,在我们的示例中,更改元素的src属性img。

我们的指令如下所示。我们再一次将它分解成碎片,我只是想给你一个概述。

LazyLoadDirective.js

我们一步一步走吧。

hookFunction

  • 允许我们在绑定元素生命周期的特定时刻触发自定义逻辑。
  • 我们使用insertedhook,因为当绑定元素已插入其父节点时会调用它(这可以保证父节点存在)。由于我们想要观察元素相对于其父(或任何祖先)的可见性,我们需要使用该钩子。

LazyLoadDirective.js

loadImage函数

  • 负责用src值替换data-url。
  • 在这个函数中,我们可以访问el应用了该指令的元素。我们可以img从那个元素中提取出来。
  • 我们检查图像是否存在,如果存在,我们添加一个监听器,它将在加载完成时触发回调函数。该回调将负责隐藏微调器并使用CSS类将动画(淡入效果)添加到图像。
  • 我们添加了第二个侦听器,当从我们的src url加载图像失败时将调用该侦听器。
  • 最后,我们用我们想要请求和显示的图像的源url 替换src我们的img元素(触发请求)。

LazyLoadDirective.js

handleIntersect函数

  • IntersectionObserver回调函数负责loadImage在某些条件下触发。
  • 当IntersectionObserver检测到元素进入视口或父组件元素时会触发它。
  • 它可以访问entries哪个是观察者和observer自己观察的所有元素的数组。
  • 我们迭代entries并检查单个条目是否对我们的用户可见isIntersecting,如果它的loadImage功能被触发
  • 请求图像后,我们unobserve将元素(从观察者的监视列表中删除),以防止再次加载图像。

LazyLoadDirective.js

createObserver 函数

  • 负责创建IntersectionObserver并将其附加到我们的元素。
  • IntersectionObserver构造函数接受一个回调(我们的handleIntersect函数),当被观察元素传递带有我们观察者选项的指定threshold和选项对象时,它会被触发。
  • optionsobject指定root这是我们的引用对象,我们在其上建立监视元素的可见性(如果我们通过,它可能是对象的任何祖先或我们的浏览器视口null)。它还指定了threshold从0到1的值,并告诉我们应该执行观察者回调的目标可见性的百分比(0表示即使一个像素可见,1表示整个元素必须可见)。
  • 在创建IntersectionObserver之后,我们使用observe方法将它附加到我们的元素。

LazyLoadDirective.js

浏览器支持

即使并非所有浏览器都支持,73%的用户(截至2018年8月28日)的覆盖率听起来还不错。

但是考虑到我们想要向所有用户显示图像(请记住使用data-url阻止图像被加载),我们需要在我们的指令中再添加一个部分。

我们需要检查浏览器是否支持IntersectionObserver,loadImage如果不支持则触发它(它将立即请求所有图像)以及createObserver是否支持。

LazyLoadDirective.js

6.注册指令

要使用我们新创建的指令,我们需要先注册它。我们可以通过两种方式实现:全局(在应用程序的任何位置都可用)或本地(在指定的组件级别)。

全球注册

要在全局注册一个指令,我们导入我们的指令并使用Vue.directive方法传递我们想要注册指令和指令本身的名称。这允许我们将v-lazyload属性添加到代码中的任何元素。

main.js

本地注册

如果我们只想在特定组件中使用我们的指令并限制对它的访问,我们可以在本地注册该指令。为此,我们需要在将使用它的组件内导入指令并在directives对象中注册它。这将使我们能够将v-lazyload属性添加到该组件中的任何元素。

7.在ImageItem组件上使用指令

注册我们的指令后,我们可以通过将v-lazyload属性添加到包含我们的img(figure在我们的例子中是标记)的父元素中来使用它。

ImageItem.vue

概要

延迟加载图像可以显着提高页面性能。它允许您仅在用户可以实际看到图像时加载图像。

对于那些仍然不相信是否值得玩它的人,我准备了一些原始数字。我们来看看我们的简单文章列表吧。目前我正在进行该测试,它有11篇带图像的文章(意思是页面上的11张图片)。我不认为这是很多图像,你可以通过进入任何新闻页面在一秒钟内找到更大的数字。

让我们坚持我们的11张图片并检查我们的页面在快速3G上的性能,只有第一篇文章可见,没有延迟加载的图像。

正如预期的11张图片,11个请求,总页面大小3.2 MB。

现在,同一页面只有第一篇文章可见和懒惰的图像。

结果,1张图片,1张请求,总页面大小1.4 MB。

通过在我们的文章中添加此指令,我们保存了10个请求并将页面大小减少了56%,请记住这是一个非常简单的示例。

相关推荐

LangChain4j如何自定义文档转换器实现数据清洗?

LangChain4j提供了3种RAG(Retrieval-AugmentedGeneration,检索增强生成)实现,我们通常在原生或高级的RAG实现中,要对数据进行清洗,也就是将外接...

Java 8 Stream API 详解(java stream.)

Java8StreamAPI详解一、概述在Java8中,StreamAPI是一个重要的新特性。它为处理集合(如List、Set等)中的元素提供了一种高效且富有表现力的方式。Str...

Java修炼终极指南:185 使用 Stream 过滤嵌套集合

这是面试中的一个经典问题,通常从一个模型开始,如下所示(我们假设集合是一个List):publicclassAuthor{privatefinalStringname;pri...

java8的stream使用小示例(java stream())

据JetBrains发布的2021年开发者生态系统调查,Java8在java使用的版本中仍然是当前最流行的版本。72%的专业开发人员使用Java8作为其在java开发中主要编程语言版本。现...

Node.js Stream - 实战篇(node.js in action)

本文转自“美团点评技术团队”http://tech.meituan.com/stream-in-action.html背景前面两篇(基础篇和进阶篇)主要介绍流的基本用法和原理,本篇从应用的角度,介...

Java Stream:集合处理的api(java 集合操作)

JavaStream流:高效集合处理的函数式编程利器一、什么是JavaStream?Java8引入的StreamAPI是一套用于处理集合数据的流式编程接口,通过函数式风格(无副作用的...

去除 List 中的重复元素,你知道几种实现方法?

去除List中重复元素,这在实际编程或面试中经常遇到,每个人都有习惯的写法吧,这里抛砖引玉,汇总了一些实现方案,开拓思路。准备数据假设数组中有10个数据,可能有重复,需要将重复的数据从数组中去掉。pu...

Java开发者必看!Stream流式编程10个爆款技巧,让你代码优雅飞起

为什么你的Java代码总像拧巴的麻绳?掌握这10个Stream实战技巧,代码效率与优雅度将产生质的飞跃。以下案例均来自真实电商系统场景,带你感受流式编程的降维打击!一、过滤与映射组合拳(Filter...

leetcode每日一题之存在重复元素(存在重复元素 iii)

题:给定一个整数数组,判断是否存在重复元素。如果存在一值在数组中出现至少两次,函数返回true。如果数组中每个元素都不相同,则返回false。比如:输入:[1,2,3,1]输出:true...

告别for循环!揭秘Stream API如何让你的代码简洁度提升300%

一、当传统循环遇上现代需求真实场景复现:某电商平台需要处理10万条订单数据,要求:筛选出金额>500的订单提取用户ID并去重统计VIP用户数量传统实现方案://常规写法Set<Long...

Java中List去重的N种方法:从基础到优雅

Java中List去重的N种方法:从基础到优雅在日常的Java开发中,我们经常会遇到需要对List集合去重的情况。无论是为了清理重复的数据,还是为了优化算法性能,掌握多种去重方式都是一项非常实用的技能...

Java Stream流没用过?常用高频方法

概念Stream流是Java8添加的以一种链式调用的方法处理数据,主要侧重于计算。具有以下相关特点代码简洁链式调用Stream常用方法1.将数组变为当作List操作String[]strArr=...

核医学专业名词索引(M-R)(核医学重点归纳)

M吗啡(morphia)埋藏式心律转复除颤器(implantablecardioverterdefibrillator,ICD)麦角骨化醇(VD2,calciferol)脉冲堆积(pulsepi...

CodeMeter 新版发布(codesigner下载)

威步于2022年8月4日发布CodeMeter7.50及CodeMeter软件保护套装11.10,以下为新版内容。CodeMeterRuntime7.50StreamingSIMDExten...

世界上最小的五轴铣床Pocket NC(最小的五轴加工中心)

PocketNC,由MIT学生研制,还有说法是这款产品的设计者是来自美国蒙大拿州的一对极客夫妻。目前主要有两款产品:PocketNCV2-50,9000美元;PocketNCV2-10,60...