图片懒加载

文章介绍了网页中大量图片使用懒加载技术提高页面加载速度和节省流量的方法。通过设置图片的data-url属性存储真实路径,初始时设置为小尺寸透明gif,当图片进入视口时,利用滚动事件和getBoundingClientRect()判断图片位置,动态替换src为真实地址来加载图片。
摘要由CSDN通过智能技术生成

背景

类似于大型的淘宝商城、京东等网页,设计大量的商品图片信息,如果我们使页面包含的所有图片一次性加载完成,那用户体验很差。
目前流行的做法是滚动动态加载,也就是懒加载,显示在屏幕之外的图片默认不加载,随着页面的滚动,图片进入了显示的范围,则触发图片的加载显示
这样做的好处,一是页面加载速度快(浏览器进度条和加载转圈很快就结束了,这样用户的体验也比较好),而是节省流量,因为不可能每一个用户会把页面从上到下滚动完

原理

存储图片的真实路径,把图片的真实路径绑定给一个以data开头的自定义属性data-url即可,页面中的img元素,如果没有src属性,浏览器就不会发出请求去下载图片(没有请求就提高了性能)

<div class="scrollLoading" data-url="loaded.html">加载中...</div>

初始化img的时候,src不能是真实的图片地址(会一次性发送请求),也不可以是空地址或者坏地址(会出现出错图标,如下所示:)
在这里插入图片描述

设置img的默认src为一张1px*1px,很小很小的gif透明图片(所有的img都用这一张,只会发送一次请求),之所以需要是透明的,是需要透出通过background设置的背景图(一张loading.png,就是一个转圈圈的背景效果图)

<img  data-url="xxx" src="1px.gif" width="180" height="180" style="background:url(loading.gif) no-repeat center;" />

需要一个滚动事件,判断元素是否在浏览器窗口,一旦进入视口才进行加载,当滚动加载的时候,就把这张透明的1px.gif图片替换为真正的url地址(也就是data-url里保存的值)

等到图片进入视口后,利用js提取data-url的真实图片地址赋值给src属性,就会去发送请求加载图片,真正实现了按需加载

方法一:滚动监听+scrollTop+offsetTop+innerHeight

浏览器可视窗口的大小
window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight

获取内容滚动的距离
window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop

获取dom元素顶部距离窗口顶部的距离
dom元素.offsetTop

在这里插入图片描述
若内容上方偏移量(scrollTop)+视口高度(innerHeight)>图片距离内容顶部的偏移量(offsetTop),则说明图片在视口内,否则说明图片在视口外。
demo

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    img {
      background: url('./img/loading.gif') no-repeat center;
      width: 250px;
      height: 250px;
      display: block;
    }
  </style>
</head>

<body>
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg"> <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">

  <script>

    let imgs = document.getElementsByTagName('img')
    // 1. 一上来立即执行一次
    fn()
    // 2. 监听滚动事件
    window.onscroll = lazyload(fn, true)
    function fn() {
      // 获取视口高度和内容的偏移量
      let clietH = window.innerHeight || document.documentElement.clientHeight || document.body.clientHeight;
      var scrollTop = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop;
      for (let i = 0; i < imgs.length; i++) {
        let x = scrollTop + clietH - imgs[i].offsetTop //当内容的偏移量+视口高度>图片距离内容顶部的偏移量时,说明图片在视口内
        if (x > 0) {
          imgs[i].src = imgs[i].getAttribute('data-url'); //从dataurl中取出真实的图片地址赋值给url
        }
      }
    }
    // 函数节流
    function lazyload(fn, immediate) {
      let timer = null
      return function () {
        let context = this;
        if (!timer) {
          timer = setTimeout(() => {
            fn.apply(this)
            timer = null
          }, 200)
        }
      }
    }


  </script>
</body>

</html>

滚动监听+getBoundingClientRect()

getBoundingClientRect()获取元素位置,这个方法没有参数

getBoundingClientRect()用于获得页面中某个元素的左,上,右和下分别相对浏览器视窗的位置。
getBoundingClientRect()是DOM元素到浏览器可视范围的距离(不包含文档卷起的部分)。

该函数返回一个Object对象,该对象有6个属性:top,lef,right,bottom,width,height;
在这里插入图片描述

	<div id="box"></div>
var object=document.getElementById('box');  
rectObject = object.getBoundingClientRect();
 
	rectObject.top:元素上边到视窗上边的距离;
	rectObject.right:元素右边到视窗左边的距离;
	rectObject.bottom:元素下边到视窗上边的距离;
	rectObject.left:元素左边到视窗左边的距离;
	rectObject.width:是元素自身的宽
	rectObject.height是元素自身的高

如果rectObject.top<=视口高度,就该加载了
demo

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <style>
    * {
      margin: 0;
      padding: 0;
    }

    img {
      background: url('./img/loading.gif') no-repeat center;
      width: 250px;
      height: 250px;
      display: block;
    }
  </style>
</head>

<body>
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <img src="./img/pixel.gif" data-url="./1.jpg">
  <script>

    let imgs = document.getElementsByTagName('img')
    // 1. 一上来立即执行一次,因为图片已经在视口内,你不滚动还不加载它了?
    fn()
    // 2. 监听滚动事件
    window.onscroll = lazyload(fn, true)
    function fn() {
      // 获取视口高度和内容的偏移量
      let offsetHeight = window.innerHeight || document.documentElement.clientHeight
      Array.from(imgs).forEach((item, index) => {
        let oBounding = item.getBoundingClientRect() //返回一个矩形对象,包含上下左右的偏移值
        console.log(index, oBounding.top, offsetHeight);
        //如果图片在视口上面,那么top就为负值,如果想图片翻上去不加载,判断条件可以写oBounding.top >= 0 && oBounding.top <= offsetHeight
        if (oBounding.top <= offsetHeight) {
          item.setAttribute('src', item.getAttribute('data-url'))
        }
      })
    }
    // 函数节流
    function lazyload(fn, immediate) {
      let timer = null
      return function () {
        let context = this;
        if (!timer) {
          timer = setTimeout(() => {
            fn.apply(this)
            timer = null
          }, 200)
        }
      }
    }


  </script>
</body>

</html>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值