前端性能优化-图片的预加载和懒加载

前言

在说到对图片资源进行优化时,那就不得不提到图片预加载和图片懒加载,可能很多朋友都了解这两者,但是一直没有很清晰的概念,以及什么时候用,用在什么场景下,今天就来详细的了解一下吧!

图片的预加载

  1. 什么是预加载?
  • 预加载就是提前加载需要用到的图片素材,在用户需要用的时候可以直接从本地缓存中获取并渲染。
  1. 预加载的原理
  • 提前加载所需要的图片资源,加载完毕后会缓存到本地,当需要时可以立马显示出来,以达到在预览的过程中,无需等待直接预览的良好体验。简而言之,就是需要显示前先加载。
  1. 为什么要使用预加载
  • 原因是,在网页全部加载之前,对一些主要内容进行加载,以提供给用户更好的体验,减少等待的时间。否则,如果一个页面的内容过于庞大,没有使用预加载技术的页面就会长时间的展现为一片空白,直到所有内容加载完毕。

预加载的实现方式

  1. css的方式
<div class="preload-pic"></div>
.preload-pic { background: url(https://img2.baidu.com/it/u=1028011339,1319212411&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=313) no-repeat }  

  1. 使用js实现,通过new Image对象设置实例对象的src属性实现图片的预加载。

    • 代码实现:
 <div class="img-container">
  <p></p>
  <img src="../../static/1.jpg" alt="图片" id="img" />
</div>
<script>
  const imgList = [
    '../../static/2.jpg',
    '../../static/3.jpg',
    '../../static/4.jpg',
    '../../static/5.jpg',
    '../../static/6.jpg',
    '../../static/7.jpg',
    '../../static/8.jpg',
    '../../static/9.jpg'
  ]

  // 当前图片下标
  let current = 0
  const getImage = document.getElementById('img')
  const p = document.querySelector('p')
  p.innerHTML = `实现预加载的效果,我是第${current + 1}张图片`
  
  //页面一开始加载数组的第一个元素
  preLoad(imgList[current]).then(data => {
    console.log(data)
  })

    // 预加载函数
    function preLoad(src) {
    return new Promise((resolve, reject) => {
      // 创建一个新的图片标签
      const image = new Image()
        // 将传进来的src赋值给新的图片
        image.src = src
      // 图片加载完成调用成功状态
      image.addEventListener('load', () => resolve(image), false)
      // 图片加载完成调用失败状态
      image.addEventListener('error', () => reject(), false)
      
    })
  }

  getImage.addEventListener('click', () => {
    // 当索引小于数组的长度时
    if (current < imgList.length) {
      // 将数组元素的src赋值给页面的元素
      getImage.src = imgList[current]
      // 当前递增值加1,下次点击变成数组的第二个元素
      current++
      p.innerHTML = `实现预加载的效果,我是第${current + 1}张图片`

      //切换图片后,同时让浏览器提前加载下一张图片
      if (current < imgList.length) {
        preLoad(imgList[current]).then(data => {
          console.log('预加载成功', data)
        })
      }
    } 
  })
</script>

图片的懒加载

  1. 什么事懒加载?
  • 懒加载其实也叫做延迟加载、按需加载,在比较长的网页或应用中,如果图片有很多,一下子之间把所有的图片都加载出来的话,耗费很多性能,而且用户不一定会把图片全部看完。只有当图片出现在浏览器的可视区域内时,让图片显示出来,这就是图片懒加载。
  1. 懒加载的原理
  • 懒加载其实也叫做延迟加载、按需加载,在比较长的网页或应用中,如果图片有很多,一下子之间把所有的图片都加载出来的话,耗费很多性能,而且用户不一定会把图片全部看完。只有当图片出现在浏览器的可视区域内时,让图片显示出来,这就是图片懒加载。
  1. 为什么使用懒加载
  • 当页面很多,内容很丰富的时候,页面很长,图片较多,比如淘宝页面,要是页面载入就一次性加载完毕,就需要等很长的时间。

懒加载的实现方式

  1. 实现方式一

    • getBoundingClientRect方法
    • 参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/getBoundingClientRect
 <div class="img-box">
      <div class="img-container">
        <img
          src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"
          alt=""
          data-src="../../static/1.jpg"
          class="lazyload"
        />
      </div>
      <div class="img-container">
        <img
          src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"
          alt=""
          data-src="../../static/2.jpg"
          class="lazyload"
        />
      </div>
      <div class="img-container">
        <img
          src="https://gitee.com/z1725163126/cloundImg/raw/master/loading.gif"
          alt=""
          data-src="../../static/3.jpg"
          class="lazyload"
        />
      </div>
    </div>
  <script>
      const getImage = [...document.querySelectorAll('.lazyload')]
      function lazyLoad() {
        getImage.forEach(item => {
          // 判断是否在可视区域内
          if (isInVisible(item)) {
          // 如果在可视区域内,就设置src的路径
            item.src = item.dataset.src
          }
        })
      }

      function isInVisible(image) {
        const rect = image.getBoundingClientRect()
        return (
          rect.bottom > 0 &&
          rect.top < window.innerHeight &&
          rect.right > 0 &&
          rect.left < window.innerWidth
        )
      }
      lazyLoad()
     // window.addEventListener('scroll', lazyLoad)
      
      /*
        优化:
        节流 :事件处理函数执行一次后,在某个时间期限内不再工作
        fun:传入一个函数
        miliseconds:间隔时间
      */

      function throttle(fun, time = 250) {
        let lastTime = 0 //最后一次执行的时间
        return function (...args) {
          const now = new Date().getTime()
          if (now - lastTime >= time) {
            fun()
            lastTime = now
          }
        }
      }
      window.addEventListener('scroll', throttle(lazyLoad, 1000), false)
    </script>
  1. 实现方式二
    • 使用IntersectionObserver API 交叉视口
    • 参考文档:https://developer.mozilla.org/zh-CN/docs/Web/API/IntersectionObserver
<script>
      // 转换成数组方便处理
      const imgList = [...document.querySelectorAll('.lazyload')]

      // 实例化构造函数
      const observer = new IntersectionObserver(entries => {
        //entries是一个数组,所以还需要遍历
        console.log(entries)
        entries.forEach(item => {
          //isIntersecting是否在可视区域展示
          if (item.isIntersecting) {
            //获取图片的自定义属性并赋值给src
            item.target.src = item.target.dataset.src
            //替换为真是src地址后取消对它的观察
            observer.unobserve(item.target)
          }
        })
      })

      //遍历所有的图片,给每个图片添加观察
      imgList.forEach(item =>  observer.observe(item))
      
    </script>
  1. 实现方式三
    • VueUse中useIntersectionObserver
    • 参考文档:https://vueuse.nodejs.cn/core/useIntersectionObserver/
// 使用自定义指令
<template>
  <div class="laz-box" v-for="item in imgList" :key="item.id">
    <img v-img-lazy="item.url" style="width: 100vw; height: 200px" />
  </div>
</template>

<script setup>
import { reactive } from 'vue'
const data = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].map(i => {
  return {
    id: `${i}`,
    url: require(`../static/${i}.jpg`)
  }
})
const imgList = reactive(data)
</script>

注册全局自定义指令:
import { useIntersectionObserver } from '@vueuse/core'
export const lazyPlugin = {
  install(app) {
    app.directive('img-lazy', {
      mounted(el, binding) {
        // el: 指令挂载到的那个元素 dom 的 img
        // binding: value 指令等于号后面表达式的值 url
        el.src = require(`../static/loading.gif`)
        const { stop } = useIntersectionObserver(el, ([{ isIntersecting }]) => {
          console.log('进入可视区域', isIntersecting)
          //判断当前监听元素是否进入视口区域
          if (isIntersecting) {
            el.src = binding.value
            el.onerror = () => {
              el.src = require(`../static/loading.gif`)
            }
            // 加载图片之后停止监听
            stop()
          }
        },
        {
          threshold: 0.5
        }
      )
      }
    })
  }
}

两者的区别

二者都是提高页面性能的有效办法,区别是一个是提前加载,一个是延迟加载甚至不加载.

  • 懒加载对服务器前端有一定的缓解压力的作用.
  • 预加载则会增加服务器前端的压力,换取更好的用户体验,这样可以使用户的操作得到最快的反映。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值