计算出盒子底边距离body(a)的距离 和 浏览器底边距离bo._img.onloa">
赞
踩
图片延迟加载:真实项目中非常重要的一个性能优化手段;
onscroll特点:
只要页面滚动就会触发 < 在浏览器最快反应时间内(谷歌4 - 6ms), 触发一次, 触发频率特别频繁 >, 重复加载a <= b的这个条件, 只要页面一直向上滚动, 在第一次符合条件后, 每次滚动条件也是符合的, 这样 lazyImage方法会被执行多次(也就是延迟加载会被处理多次)
处理频率太快,我们需要降低他的频率 函数的节流throttle
意义: 如果不做延迟加载,那么页面渲染的时候,同时也要把资源请求回来,并且进行渲染,这样会阻碍页面的渲染进度,导致首次加载页面变慢,延迟加载一方面,可以提高页面加载速度,另外一方面也可以减少用户没必要的网路消耗
需要延迟加载的图片放置在一个盒子中,
盒子有一个默认占位的背景图,在没有加载真实图片之前,我们给用户呈现的是一个默认的占位图
img一开始不能设置src,因为器一但设置src页面加载的时候,就会加载图片了,达不到延迟加载的效果
把真实加载的图片地址放到image的lazy-image自定义属性上(自定义属性名自己设定即可)
注意: 开始图片是隐藏的:在某些IE浏览器中,如果图片的SRC是空的,或者加载的图片是错误的,图片不隐藏,会显示一个 X 的效果,很难看,所以图片没有加载真实地址,并且加载正确之前,还是让图片隐藏吧!
- //节流函数
- function throttle(func, wait = 500) {
- let timer = null,
- previous = 0;
- return function anonymous(...params) {
- let now = new Date(),
- remaining = wait - (now - previous);
- if (remaining <= 0) {
- clearTimeout(timer);
- timer = null;
- previous = now;
- func.call(this, ...params);
- } else if (!timer) {
- timer = setTimeout(() => {
- clearTimeout(timer);
- timer = null;
- previous = new Date();
- func.call(this, ...params);
- }, remaining);
- }
- };
- }
-
- //盒子顶部距离body上偏移
- function offset(element) {
- let l = element.offsetLeft,
- t = element.offsetTop,
- p = element.offsetParent;
- while (p && p.tagName !== 'body') {
- if (!/MSIE 8/.test(navigator.userAgent)) {
- l += p.clientLeft;
- t += p.clientTop;
- }
- l += p.offsetLeft;
- t += p.offsetTop;
- p = p.offsetParent;
- }
- return {
- top: t,
- left: l
- };
- }
-
- //获取占位盒子 && html
- let imageLazyBox = document.querySelector('.imageLazyBox'),
- html = document.documentElement;
-
- //执行lazyImage方法,传递需要延迟加载的盒子,实现单张图片延迟加载
- function lazyImage(imageLazyBox) {
- // 获取图片
- let imageItem = imageLazyBox.querySelector('img'),
- // 获取图片的自定义属性
- lazy_image = imageItem.getAttribute('lazy-image');
- // if (lazy_image === null) return;//性能不好
- imageItem.onload = function () {
- //当图片加载成功后触发的触发 onload vs onerror
- imageItem.style.opacity = 1;
- };
- //图片的地址赋值给image的src
- imageItem.src = lazy_image;
- // 也有在不论图片是否加载成功,只要处理过,则就把lazy-image属性移除掉(证明其已经处理过了)
- imageItem.removeAttribute('lazy-image');
- //第一次执行这个方法,我们设置一个自定义属性isload = true 证明当前图片已经看过了
- imageLazyBox.isload = true;
- }
-
- //监听滚动条图片全部显示后加载图片
- window.onscroll = throttle(function () {
- console.log('ok');
- if (imageLazyBox.isload) return;
- // 盒子底部距离body的距离:盒子顶部的距离+盒子本身高度
- let a = offset(imageLazyBox).top + imageLazyBox.offsetHeight,
- // 浏览器底边距离body: 一屏的高度-滚动条卷去的高度
- b = html.clientHeight + html.scrollTop;
- if (a <= b) {
- lazyImage(imageLazyBox)
- }
- })
-
-
- //设定定时器,延迟多久之后进行加载
- // setTimeout(lazyImage, 1000);
-
- // 或者触发条件:页面中所有资源都加载完成
- // window.onload = function () { };

思路: //在浏览器滚动条滚动(页面滚动)过程中,等待图片完全出现在可视窗口内的时候,我们加载真实图片 "这是非首屏图片的处理步骤"-->计算出盒子底边距离body(a)的距离 和 浏览器底边距离body(b)的距离 做比较如果a<=b的时候加载真实图片即可
思路:基于getBoundingClientRect来判断图片的加载条件,不用自己写offset方法了
- function throttle(func, wait = 500) {
- let timer = null,
- previous = 0;
- return function anonymous(...params) {
- let now = new Date(),
- remaining = wait - (now - previous);
- if (remaining <= 0) {
- clearTimeout(timer);
- timer = null;
- previous = now;
- func.call(this, ...params);
- } else if (!timer) {
- timer = setTimeout(() => {
- clearTimeout(timer);
- timer = null;
- previous = new Date();
- func.call(this, ...params);
- }, remaining);
- }
- };
- }
-
- let imageLazyBox = document.querySelector('.imageLazyBox'),
- html = document.documentElement;
-
- function lazyImage(imageLazyBox) {
- let imageItem = imageLazyBox.querySelector('img'),
- lazy_image = imageItem.getAttribute('lazy-image');
- imageItem.onload = function () {
- imageItem.style.opacity = 1;
- };
- imageItem.src = lazy_image;
- imageItem.removeAttribute('lazy-image');
- imageLazyBox.isload = true;
- }
-
- window.onscroll = throttle(function () {
- //获取当前盒子距离浏览器可视窗口的位置信息
- let a = imageLazyBox.getBoundingClientRect().bottom,
- // 可视窗口一屏的的大小
- b = html.clientHeight;
- if (imageLazyBox.isload) return;
- if (a <= b) {
- lazyImage(imageLazyBox)
- }
- })

基于 IntersectionObserver实现图片延迟加载
设置一个监听器,后期可以监听指定的dom元素(可以多个),当监听的元素dom元素与可视窗口交叉位置发生改变,触发回调函数执行,-->changes是一个集合,集合中存储了一个dom元素与可视窗口交叉的状态信息
Observer.observe(imageLazyBox)监听dom元素
Observer.unobserve(imageLazyBox):解除监听
默认:第一次监听dom触发一次页面刚开始出现在页面中触发一次,元素消失在页面中触发一次
基于threshold配置项,控制触发监听条件,(0刚出现, 0.5出现一半, 1完全出现)
- let imageLazyBox = document.querySelector('.imageLazyBox'),
- //配置项只有完全触发出现
- options = {
- threshold: [1]
- };
- function lazyImage(imageLazyBox) {
- let imageItem = imageLazyBox.querySelector('img'),
- lazy_image = imageItem.getAttribute('lazy-image');
- imageItem.onload = function () {
- imageItem.style.opacity = 1;
- };
- imageItem.src = lazy_image;
- imageItem.removeAttribute('lazy-image');
- imageLazyBox.isload = true;
- }
- let ob = new IntersectionObserver(change => {
- // item监听的dom元素与可视窗口的交叉信息
- // target存储当前监听的那个盒子
- let item = change[0],
- target = item.target;
- if (item.isIntersecting) {
- //符合条件:盒子已经完全出现在视口中
- lazyImage(target);
- // 处理过一次延迟加载,以后当前这个元素无需在次监听处理了
- ob.unobserve(imageLazyBox)
- }
- }, options)
- //监听dom元素
- ob.observe(imageLazyBox)

基于IntersectionObserver,实现延迟加载,相对于之前 window.onscroll实现延迟加载的优势
Can I use... Support tables for HTML5, CSS3, etc测试方法兼容性的
loading="lazy" 浏览器会自己计算该何时加载,帮助我们加载真实的图片
<img src="images/1.jpg" loading="lazy">
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。