图片懒加载

图片懒加载

简介

  • 图片懒加载是一种前端性能优化技术,它通过延迟非关键资源(如图片)的加载时机,直到这些资源即将被用户看到内或者经过一定的延迟后,才开始加载,从而减少初次页面加载的时间和数据使用量,提高用户体验。
  • 本文总结的图片懒加载技术依赖vue,并将其封装为一个插件
  • 支持组件可见或即将可见时懒加载
  • 支持加载真实组件前展示骨架组件,提高用户体验

涉及的属性

非响应式

1.timeout:

  • 类型:Number
  • 作用:指定延迟加载的时间(以毫秒为单位)。如果设置了这个属性,组件将在指定时间后初始化。

2、tagName:

  • 类型:String
  • 默认值:’div’
  • 作用:指定包裹内容的 HTML 标签名称。默认是 div,可以根据需要更改为其他标签。

3、viewport:

  • 类型:HTMLElement 或 Object
  • 默认值:null
  • 作用:指定视口元素,用于 IntersectionObserver。如果没有指定,默认是 null,表示使用浏览器的视口。

4、threshold:

  • 类型:String
  • 默认值:’0px’
  • 作用:指定触发懒加载的阈值。可以设置为像素值或百分比,例如 ‘100px’ 或 ‘50%’。

5、direction:

  • 类型:String
  • 默认值:’vertical’
  • 作用:指定滚动方向。可以是 ‘vertical’(垂直方向)或 ‘horizontal’(水平方向)。

6、maxWaitingTime:

  • 类型:Number
  • 默认值:50
  • 作用:指定最大等待时间(以毫秒为单位),用于 requestAnimationFrame 回调,防止主线程卡顿。

这些属性允许用户在使用 VueLazyComponent 时进行灵活配置,以满足不同的需求。

响应式

1、isInit:

  • 类型:Boolean
  • 默认值:false
  • 作用:表示组件是否已经初始化。当组件完成初始化时,这个值会被设置为 true。

2、timer:

  • 类型:null 或 Number
  • 默认值:null
  • 作用:用于存储定时器的引用。如果设置了 timeout 属性,组件会在指定时间后初始化,这个定时器用于实现这个功能。

3、io:

  • 类型:null 或 IntersectionObserver
  • 默认值:null
  • 作用:用于存储 IntersectionObserver 的实例。IntersectionObserver 用于检测组件是否进入视口,以便延迟加载内容。

4、loading:

  • 类型:Boolean
  • 默认值:false
  • 作用:表示组件是否正在加载内容。当组件开始加载内容时,这个值会被设置为 true。

这些数据属性用于管理组件的状态和行为。通过响应式的数据属性,Vue.js 可以在数据变化时自动更新视图,从而实现动态和交互式的用户界面。

功能详解

懒加载内容

  • IntersectionObserver是浏览器内置API,用于异步观察一个目标元素与其祖先元素或顶级文档视口(viewport)交叉状态的变化。它可以用于实现懒加载、无限滚动、广告曝光监测等功能。

  • IntersectionObserver 构造函数用于创建一个新的 IntersectionObserver 实例。它接受两个参数:

    • 回调函数(callback):当目标元素的可见性发生变化时,这个回调函数会被调用。
    • 选项对象(options):用于配置 IntersectionObserver 的行为。
      可选参数,用于配置 IntersectionObserver 的行为。包含以下属性:
      • root:指定用作视口的元素,必须是目标元素的祖先元素。默认是浏览器的视口。
      • rootMargin:用于扩展或缩小 root 元素的边界,类似于 CSS 的 margin 属性。可以使用像素值或百分比。
      • threshold:一个数值或数值数组,表示目标元素的可见比例达到这些值时,回调函数会被触发。

骨架展示

模板中的条件渲染:

  • 使用 v-if 和 v-else-if 指令根据 isInit 状态渲染实际内容或骨架屏。
  • isInit 为 false 时显示骨架屏,为 true 时显示实际内容。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<template>
<transition-group :tag="tagName" name="lazy-component" style="position: relative;"
@before-enter="(el) => $emit('before-enter', el)"
@before-leave="(el) => $emit('before-leave', el)"
@after-enter="(el) => $emit('after-enter', el)"
@after-leave="(el) => $emit('after-leave', el)"
>
<div v-if="isInit" key="component">
<slot :loading="loading"></slot>
</div>
<div v-else-if="$slots.skeleton" key="skeleton">
<slot name="skeleton"></slot>
</div>
<div v-else key="loading">
</div>
</transition-group>
</template>

过渡动画

transition-group:

  • 使用 transition-group 包裹内容,实现内容切换时的过渡动画。
  • 通过 @before-enter、@before-leave、@after-enter 和 @after-leave 事件触发父组件的相应事件。

事件通知

在组件生命周期的不同阶段触发事件,通知父组件。

逻辑

  • 首先搞清楚,这里的懒加载是指以显示骨架内容代替真实数据,,等到有需要的时候再加载真实数据。

  • 在视口加载和超过设定时长自动加载,两者通过timeout属性决定,timeout为true使用延时加载,否则使用视口加载模式

  • 初始化是指加载真实数据的组件,即将loading指改为true。

  • 在挂载时,如果timeout值为加假,说明要使用视口交叉来懒加载图片。需要初始化视口交叉监视API:IntersectionObserver

  • 在创建阶段,如果指定timeout则无论可见与否都是在timeout之后初始化

  • 销毁:在组件销毁前取消观察

  • 然后这里还定义了一些自定义函数,供插件使用者监听组件的状况。