在js中图片的懒加载理解分析
发布日期:2021-05-08 01:28:03 浏览次数:28 分类:原创文章

本文共 4267 字,大约阅读时间需要 14 分钟。

一、懒加载的理解

  1. 懒加载:
    1)懒加载其实就是延迟加载,是一种对网页性能优化的方式,比如当访问一个页面的时候,优先显示可视区域的图片而不一次性加载所有图片,当需要显示的时候再发送图片请求,避免打开网页时加载过多资源
    2)在图片非常多的应用场景,为了提高页面加载速度,改善用户体验,我们对未出现在视野范围内的图片先不进行加载,等到出现在视野范围才去加载
    3)懒加载(LazyLoad)是前端优化的一种有效方式,极大的提升用户体验

  2. 懒加载的运用场景:
    1)当页面中需要一次性载入很多图片的时候,往往都是需要用懒加载的
    2)如果一次ajax请求数量过多的图片,把它们全部加载出来,会显示的很慢,对于用户的显示体验造成很大的影响

  3. 懒加载的原理:
    先把img的src指向空或者一个小图片,图片真实的地址存储在img一个自定义的属性里,< img src=”” data-src=”http://real.com/real.jpg” />,等到此图片出现在视野范围内了,获取img元素,把data-src里的值赋给src

  4. 判断元素是否在可视区域
    1)通过document.documentElement.clientHeight获取屏幕可视窗口高度
    通过element.offsetTop获取元素相对于文档顶部的距离
    通过document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
    判断element.offsetTop - document.documentElement.scrollTop < document.documentElement.clientHeight是否成立,如果成立,元素就在可视区域内
    2)通过getBoundingClientRect()方法来获取元素的大小以及位置,这个方法返回一个名为ClientRect的DOMRect对象,包含了top、right、botton、left、width、height这些值
    bound.top<=clientHeight的时候,图片是在可视区域的
    封装代码如下:

function isInSight(el) {     const bound = el.getBoundingClientRect();  const clientHeight = window.innerHeight;  //如果只考虑向下滚动加载  //const clientWidth = window.innerWeight;  return bound.top <= clientHeight + 100;}

3)IntersectionObserver可以自动观察元素是否在视口内
可以用到intersectionRatio来判断是否在可视区域内,当intersectionRatio > 0 && intersectionRatio <= 1即在可视区域内
封装代码如下:

var io = new IntersectionObserver(callback, option);// 开始观察io.observe(document.getElementById('example'));// 停止观察io.unobserve(element);// 关闭观察器io.disconnect();
  1. 加载图片
    1)页面打开时需要对所有图片进行检查,是否在可视区域内,如果是就加载
    2)封装代码如下:
function checkImgs() {     const imgs = document.querySelectorAll('.my-photo');  Array.from(imgs).forEach(el => {       if (isInSight(el)) {         loadImg(el);    }  })}function loadImg(el) {     if (!el.src) {       const source = el.dataset.src;    el.src = source;  }

说明:优化的地方是设一个标识符标识已经加载图片的index,当滚动条滚动时就不需要遍历所有的图片,只需要遍历未加载的图片即可

  1. 函数节流优化
    1)在类似于滚动条滚动等频繁的DOM操作时,可以进行函数节流和函数去抖
    2)函数节流:让一个函数不要执行的太频繁,减少一些过快的调用来节流
    3)基本步骤:
    获取第一次触发事件的时间戳
    获取第二次触发事件的时间戳
    时间差如果大于某个阈值就执行事件,然后重置第一个时间
    4)封装代码如下:
function throttle(fn, mustRun = 500) {     const timer = null;  let previous = null;  return function() {       const now = new Date();    const context = this;    const args = arguments;    if (!previous){         previous = now;    }    const remaining = now - previous;    if (mustRun && remaining >= mustRun) {         fn.apply(context, args);      previous = now;    }  }}

说明:mustRun就是调用函数的时间间隔,无论多么频繁的调用fn,只有remaining>=mustRun时fn才能被执行

二、懒加载的实现

  1. 简单的懒加载实现
    1)html 部分:
<!--data-* 全局属性:构成一类名称为自定义数据属性的属性,可以通过HTMLElement.dataset来访问--><img src="" data-src="./images/1.jpg" ><img src="" data-src="./images/2.jpg" ><img src="" data-src="./images/3.jpg" ><img src="" data-src="./images/4.jpg" ><img src="" data-src="./images/5.jpg" ><img src="" data-src="./images/6.jpg" ><img src="" data-src="./images/7.jpg" ><img src="" data-src="./images/8.jpg" >

2)js部分:

window.onload = function(){           // 获取元素        var img = document.querySelectorAll("img");        var len = img.length;        // 存储图片的加载位置        var n = 0;        // 获取图片的可视区域        var height = document.documentElement.clientHeight;        var top = document.body.scrollTop || document.documentElement.scrollTop;        for(var i=n;i<len;i++){               if(img[i].offsetTop< height + top){                   if(img[i].getAttribute("src")==""){                       img[i].src = img[i].getAttribute("data-src");                }                n = i + 1;                console.log("第"+n+"张图片"+",n="+n);            }        }    };

3)在当打开页面的时候
console 控制台输出:
在这里插入图片描述

network 网络输出:
在这里插入图片描述

4)在打开页面滚动的时候
console 控制台输出:
在这里插入图片描述
network 网络输出:
在这里插入图片描述
5)通过在打开页面的时候,网页中的图片是没有全部加载出来的,从network中可以看出只加载出了两张图片资源。在打开页面进行滚动以后,后面的图片资源才慢慢加载出来,在network中看出,但是也只是展示出了五张图片的资源,展示出了我们的可视区域,剩下的图片也是没有加载出来,这样恰恰就可以实现了图片的懒加载,保证一次请求不会请求所有的资源,在出现可视区域后才会加载出来,提高了前端的性能优化

  1. 懒加载的封装函数
    1)代码如下:
function checkImgs() {     const imgs = Array.from(document.querySelectorAll(".my-photo"));  imgs.forEach(item => io.observe(item));}function loadImg(el) {     if (!el.src) {       const source = el.dataset.src;    el.src = source;  }}const io = new IntersectionObserver(ioes => {     ioes.forEach(ioe => {       const el = ioe.target;    const intersectionRatio = ioe.intersectionRatio;    if (intersectionRatio > 0 && intersectionRatio <= 1) {         loadImg(el);    }    el.onload = el.onerror = () => io.unobserve(el);  });});
上一篇:在js中的瀑布流布局理解
下一篇:在js中的Debounce 和 Throttle 的原理及实现

发表评论

最新留言

不错!
[***.144.177.141]2025年03月28日 12时41分10秒