什么是懒加载

懒加载其实就是延迟加载,是一种对网页性能优化可方式,比如当访问一个页面的时候,优先显示可视区域的图片而不一次性加载所有图片,当需要显示的时候再发送图片请求,避免打开网页时加载过多资源。

什么时候用懒加载

当页面中需要一次性载入很多图片的时候,往往都是需要用懒加载的。

懒加载原理

我们都知道HTML中的 <img>标签是代表文档中的一个图像。。说了个废话。。

<img>标签有一个属性是 src,用来表示图像的URL,当这个属性的值不为空时,浏览器就会根据这个值发送请求。如果没有 src属性,就不会发送请求。

嗯?貌似这点可以利用一下?

我先不设置 src,需要的时候再设置?

nice,就是这样。

我们先不给 <img>设置 src,把图片真正的URL放在另一个属性 src中,在需要的时候也就是图片进入可视区域的之前,将URL取出放到 src中。

实现

HTML结构

<div class="container"><div class="img-area"><img class="my-photo" alt="loading" src="./img/img1.png"></div><div class="img-area"><img class="my-photo" alt="loading" src="./img/img2.png"></div><div class="img-area"><img class="my-photo" alt="loading" src="./img/img3.png"></div><div class="img-area"><img class="my-photo" alt="loading" src="./img/img4.png"></div><div class="img-area"><img class="my-photo" alt="loading" src="./img/img5.png"></div>
</div>

仔细观察一下, <img>标签此时是没有 src属性的,只有 alt和 src属性。

alt 属性是一个必需的属性,它规定在图像无法显示时的替代文本。 data-* 全局属性:构成一类名称为自定义数据属性的属性,可以通过 HTMLElement.dataset来访问。

如何判断元素是否在可视区域

方法一

网上看到好多这种方法,稍微记录一下。

  1. 通过 document.documentElement.clientHeight获取屏幕可视窗口高度
  2. 通过 document.documentElement.scrollTop获取浏览器窗口顶部与文档顶部之间的距离,也就是滚动条滚动的距离
  3. 通过 element.offsetTop获取元素相对于文档顶部的距离

然后判断②-③<①是否成立,如果成立,元素就在可视区域内。

方法二(推荐)

通过 getBoundingClientRect()方法来获取元素的大小以及位置,MDN上是这样描述的:

The Element.getBoundingClientRect() method returns the size of an element and its position relative to the viewport.

这个方法返回一个名为 ClientRect的 DOMRect对象,包含了 top、 right、 botton、 left、 width、 height这些值。

MDN上有这样一张图:

可以看出返回的元素位置是相对于左上角而言的,而不是边距。

我们思考一下,什么情况下图片进入可视区域。

假设 constbound=el.getBoundingClientRect();来表示图片到可视区域顶部距离; 并设 constclientHeight=window.innerHeight;来表示可视区域的高度。

随着滚动条的向下滚动, bound.top会越来越小,也就是图片到可视区域顶部的距离越来越小,当 bound.top===clientHeight时,图片的上沿应该是位于可视区域下沿的位置的临界点,再滚动一点点,图片就会进入可视区域。

也就是说,在 bound.top<=clientHeight时,图片是在可视区域内的。

我们这样判断:

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

这里有个+100是为了提前加载。

加载图片

页面打开时需要对所有图片进行检查,是否在可视区域内,如果是就加载。

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,当滚动条滚动时就不需要遍历所有的图片,只需要遍历未加载的图片即可。

函数节流

在类似于滚动条滚动等频繁的DOM操作时,总会提到“函数节流、函数去抖”。

所谓的函数节流,也就是让一个函数不要执行的太频繁,减少一些过快的调用来节流。

基本步骤:

  1. 获取第一次触发事件的时间戳
  2. 获取第二次触发事件的时间戳
  3. 时间差如果大于某个阈值就执行事件,然后重置第一个时间
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才能被执行。

实验

页面打开时

可以看出此时仅仅是加载了img1和img2,其它的img都没发送请求,看看此时的浏览器

第一张图片是完整的呈现了,第二张图片刚进入可视区域,后面的就看不到了~

页面滚动时

当我向下滚动,此时浏览器是这样

此时第二张图片完全显示了,而第三张图片显示了一点点,这时候我们看看请求情况

img3的请求发出来,而后面的请求还是没发出~

全部载入时

当滚动条滚到最底下时,全部请求都应该是发出的,如图

更新

方法三 IntersectionObserver

经大佬提醒,发现了这个方法

先附上链接:

jjc大大:

https://github.com/justjavac/the-front-end-knowledge-you-may-dont-know/issues/10

阮一峰大大:

http://www.ruanyifeng.com/blog/2016/11/intersectionobserver_api.html

API Sketch for Intersection Observers:

https://github.com/WICG/IntersectionObserver

IntersectionObserver可以自动观察元素是否在视口内。

var io = new IntersectionObserver(callback, option);
// 开始观察
io.observe(document.getElementById('example'));
// 停止观察
io.unobserve(element);
// 关闭观察器
io.disconnect();

callback的参数是一个数组,每个数组都是一个 IntersectionObserverEntry对象,包括以下属性:

属性描述time可见性发生变化的时间,单位为毫秒rootBounds与getBoundingClientRect()方法的返回值一样boundingClientRect目标元素的矩形区域的信息intersectionRect目标元素与视口(或根元素)的交叉区域的信息intersectionRatio目标元素的可见比例,即intersectionRect占boundingClientRect的比例,完全可见时为1,完全不可见时小于等于0target被观察的目标元素,是一个 DOM 节点对象

我们需要用到 intersectionRatio来判断是否在可视区域内,当 intersectionRatio>0&&intersectionRatio<=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);});
});

源自:segmentfault
声明:文章著作权归作者所有,如有侵权,请联系小编删除。

img标签显示不出图片_前端开发,原生 JS 实现最简单的图片懒加载相关推荐

  1. 懒加载和预加载的区别_类的动态创建(ro,rw)amp; 懒加载类和非懒加载类底层加载的区别 amp; 类和分类的搭配分析...

    黑客技术点击右侧关注,了解黑客的世界! Java开发进阶点击右侧关注,掌握进阶之路! Python开发点击右侧关注,探讨技术话题!作者丨OSMin链接:https://juejin.im/post/5 ...

  2. java懒加载的原理_每天使用 Spring 框架,那你知道 lazy-init 懒加载原理吗?

    普通的bean的初始化是在容器启动初始化阶段执行的,而被lazy-init修饰的bean 则是在从容器里第一次进行context.getBean("")时进行触发. Spring ...

  3. 如何在input输入框中加一个搜索的小图片_前端开发困难重重,如何把握机会学习?...

    第3天[form表单] 主要内容 Form表单 表单元素 表单元素的属性 HTML5新增type类型 HTML新增属性 学习目标 一.Form表单 表单在 Web 网页中用来给访问者填写信息,从而能采 ...

  4. html table导出excel 插入图片_前端 Table 用 JS 导出EXCEL(支持大量数据,保留报表格式) - pensive2019...

    最近项目上,需要用到将网页上的table报表导出Excel.原先一直用,面对简单的数结构时只要简单的套用就能导出了,但是table结构相对复杂时,很难在组成一样结构,要花很多时间调:这时就想到在百度上 ...

  5. dw自动滚动图片_3分钟搞定图片懒加载

    什么是图片懒加载 图片的懒加载就是在页面打开的时候,不要一次性全部显示页面所有的图片,而是只显示当前视口内的图片,一般在移动端使用(PC端主要是前端分页或者后端分页). 为什么需要懒加载 对于一个页面 ...

  6. 前端性能优化总结/懒加载、函数节流、优化dom操作、雪碧图、合并文件

    1.减少 HTTP 请求数量 在浏览器与服务器进行通信时,主要是通过 HTTP 进行通信.浏览器与服务器需要经过三次握手,每次握手需要花费大量时间.而且不同浏览器对资源文件并发请求数量有限(不同浏览器 ...

  7. iframe懒加载_懒加载是如何实现的?

    作为网页内容的一部分,图像和视频通常要消耗很多资源加载.要提高网页应用的性能,如何避免资源浪费在加载图像和视频上就很重要了.但是,很多时候我们都不愿意减少网页上的媒体资源,所以我们经常无从下手.幸运的 ...

  8. JQuery实现网页图片懒加载

    使用img标签加载图片,在网页上显示图片,这里就简单的设置一下样式了,主要目的是展示图片的不同加载方式. 1.普通实现方式 普通的实现方式就是不做任何处理,需要使用到图片时就去加载图片,这些图片一般存 ...

  9. jquery之图片懒加载(总结)

    2019独角兽企业重金招聘Python工程师标准>>> 在包含很多大图片长页面中延迟加载图片可以加快页面加载速度. 浏览器将会在加载可见图片之后即进入就绪状态. 在某些情况下还可以帮 ...

  10. 实现图片懒加载(及优化相关)

    目录 内容介绍 1.懒加载 2.预加载 一.效果展示 二.实现代码 三.优化相关 内容介绍   工作之余想要休闲一下(看-美-女-图),但是又觉得单纯休闲不利于自身进步,于是 --   首先,简单说一 ...

最新文章

  1. 关系运算符、逻辑 运算符与三元运算符
  2. 【阿里云 Linux 服务器】在阿里云购买的 Linux 或者 Windows 服务器,在用 putty 访问的时候不知道用户名密码怎么办?
  3. 高并发场景下 disk io 引发的高时延问题
  4. 苹果新的编程语言 Swift 语言进阶(一)--综述
  5. [蓝桥杯2017初赛]九宫幻方-数论+next_permutation枚举
  6. 收回软键盘的两种方式
  7. 面试官系统精讲Java源码及大厂真题 - 46 ServerSocket 源码及面试题
  8. C#LeetCode刷题-队列
  9. BZOJ.1005.[HNOI2008]明明的烦恼(Prufer 高精 排列组合)
  10. 认识Blend 3工作区
  11. springboot设置局域网访问
  12. C++著名库的比较和学习经验
  13. NPOI导出excel设置打印为A4纸张
  14. 计算机卡住了怎样恢复,电脑死机按什么键恢复
  15. 04-Kubernetes 创建资源
  16. uni-app——如何获取页面容器的高度
  17. C语言 求最大值和最小值
  18. 李阳疯狂英语-228句口语要素
  19. 17.AtomicInteger、AtomicBoolean的底层原理
  20. 【电路分析】拉普拉斯变换及其应用

热门文章

  1. gtid mysql failover_说GTID - Failover and Scaleout
  2. PTA 程序设计天梯赛(101~120题)
  3. Flutter学习 — 添加Material触摸水波效果
  4. Android SwipeRefreshLayout 实现下拉刷新2
  5. Eclipse — 如何导入MySQL驱动
  6. eclipse—安装ADT插件搭建安卓开发环境
  7. Web — 概述、国际标准概述、特点+扩展名类型
  8. Android ViewPager + PagerAdapter 实现轮播图
  9. Python 的解释器
  10. 移植opencv2.4.9到android过程记录