前端性能优化之图片懒加载

108 阅读4分钟

前言

在我们项目开发过程中,图片加载是一个很常见的场景。但是你是否想过一个问题,随着图片需要加载的数量非常大时候会出现什么问题呢?那么我们就来讨论讨论吧。

原理分析

我们如果在代码中没有对图片资源做特殊处理的话,每个图片都是需要浏览器去下载下来,但是随着图片数量的增加,浏览器下载图片的所花费的时间也会随之增加,要是在网络环境较差的环境下就非常容易出现页面卡顿或者白屏的情况,这极大的影响了用户体验。我们在开发的过程是需要考虑用户体验的,前端的职责不仅在于绘制美丽的页面,更重要的是吸引更多的用户以及良好的用户体验。

如何解决

这种需求是非常常见的,我们一般采用图片懒加载技术。当图片需要被加载出来的时候,我们才让浏览器去下载该图片,这样就会很好的减轻了浏览器的压力,每次都按需加载。

懒加载:延迟加载,对于一个很长迭代页面,优先加载可视区域的内容,其他部分等进入可视区时再加载。

话不多说,我们就来实现一下懒加载。

实现思路

图片懒加载的关键就是要判断图片的位置是否进入了可视区。

我们可以通过监听scroll事件获取img元素相对于视口的顶点位置el.getBoundingClientRect().top,只要这个值小于浏览器的高度window.innerHeight说明进入可视区,当图片进入可视区时再去加载图片资源。

我们首先给每个图片的src赋值为一个默认的图片,当进入可视区后,利用自定义属性data-src的真实地址给src。

在此之前,我们需要了解一下src和自定义属性data- 。

IMG属性

在HTML的<img>标签的src属性是用来指定图片来源的核心属性,它有几个重要的特点:

  1. 必备属性

    • src是<img>标签的必需属性,没有它图片无法显示
    • 如果src指向的资源不存在,会显示破损图片图标
  2. 支持多种路径格式

    • 相对路径、绝对路径、完整URL、Data URLs(内嵌图片)
  3. 动态修改

    • 可以通过JavaScript动态改变src的值
  4. 预加载机制

    • 浏览器看到img标签会立即开始下载图片,即使图片还没有进入可视区
  5. 跨域限制

    • 从其他域名加载图片时需要考虑CORS策略,特别是在canvas操作中
  6. 响应式支持

    • 现代开发中常配合srcset属性实现响应式图片
自定义属性

在HTML5引入了非常有用的特性,即自定义属性(data-* 属性),几乎所有的HTML标签都可以使用data- 属性

data-* 属性允许我们在HTML元素上存储自定义数据,而不会影响页面的布局或样式

自定义属性需要遵守以下规则:

  • 必须以data- 开头
  • 属性名只能包含小写字母、数字、连字符(-)、点(.)、冒号(:)、下划线(_)
  • 不能包含大写字母
  • 不能以xml开头

我们想要获取自定义属性可以使用以下方法: 方法一:使用dataset属性

const element = document.querySelector('div')

// 读取 data-user-id
console.log(element.dataset.userId) // "123"

// 读取 data-last-login  
console.log(element.dataset.lastLogin) // "2024-01-15"

// 设置新的data属性
element.dataset.newProperty = "新值"

方法二:使用getAttribute/setAttribute

// 读取
const userId = element.getAttribute('data-user-id')

// 设置
element.setAttribute('data-status', 'active')

我们使用自定义属性有以下几点需要注意:

  1. 数据类型
    • data属性的值始终是字符串
    • 需要其他类型时需要手动转换
  2. 性能考虑
    • 不要存储大量数据
    • 敏感信息不要放在data属性中(用户可见)
  3. 命名转换
// HTML中的连字符会转换为驼峰命名
// data-user-name -> dataset.userName
// data-last-login-time -> dataset.lastLoginTime

接着,我们回归正题。怎么判断图片是否进入可视区呢? 那么,我们就需要知道几个浏览器的位置属性了。

image.png

代码实现

// 当初始的HTML 文档被完全加载和解析完成之后,运行函数
document.addEventListener('DOMContentLoaded',function(){
    lazyloader()
})

// 当页面滚动时,运行函数
document.addEventListener('scroll',lazyloader)

function lazyloader(){
    document.querySelectorAll('img.lazy[data-src]').forEach(function(img)){
        let rect=img.getBoundingClientRect()
        let visible=rect.top<=window.innerHeight&&rect.bottom>=0
        if(!visible) return
        // 如果元素进入可视区,则替换src
        img.src=img.dataset.src
        img.classList.remove('lazy')
    }
}

Ending

以上内容就是图片懒加载的实现了,在一定程度上减轻了浏览器的渲染压力。聪明的你,请继续想想还有什么地方可以再优化一下吗?那就敬请期待我们下一次讨论这个问题吧!