jquery 加载显示loading图标_【JS】322 手把手教你实现前端惰性加载

本文由 chunpengliu

80ea2cec50af75c6c885712a318f1f47.png

从需求出发:

在实际的项目开发中,我遇到了一个这样的需求:一个页面模块有很多列表数据展示,每条数据都带有图片,而首次展示的图片只需要不到10张,那么我们还要一次性把所有图片都加载出来吗?显然这是不对的,不仅影响页面渲染速度,还浪费带宽(因为需要对列表进行拖动排序,需加载出全部列表,不能做分页)。我们可以在浏览器滚动到一定的位置的时候进行下载,这也就是们通常所说的惰性加载,技术上现实其中要用的技术就是图片懒加载--到可视区域再加载。

67ff9d5100ef94742afc9dcebdc9a384.gif

实现方案:

1、默认不加载图片,只加载占位符2、组件滚动条变化3、计算可视区域,触发条件4、标签src属性加载资源

知识点:

scrollTop:外框元素的滚动高度offsetTop:元素相对于最近的包含该元素的定位元素(具有position属性且不是static)边框的距离。如果没有定位的元素,则默认body。offsetHeight:它返回该元素的像素高度,高度包含该元素的垂直内边距和边框,且是一个整数。计算:可视区域的高度(offsetHeight) + 滚动条卷去的高度(scrollTop) >= 元素相对于外框的距离(offsetTop) - 偏移量 (提前加载)

ae60980cccea491d481f97fc4e18243f.png

代码实现:

页面结构

type="text/css">

.container{

   width:200px;

   height:200px;

   position:relative;

   overflow-y:scroll;

}

.img-area{

   width:100px;

   height:100px;

}

class="container">

   

class="img-area">

        class="pic" alt="loading" src="./img/img1.png" src="image-placeholder-logo.svg">

   

class="img-area">

        class="pic" alt="loading" src="./img/img2.png" src="image-placeholder-logo.svg">

   

class="img-area">

        class="pic" alt="loading" src="./img/img3.png" src="image-placeholder-logo.svg">

   

class="img-area">

        class="pic" alt="loading" src="./img/img4.png" src="image-placeholder-logo.svg">

   

class="img-area">

        class="pic" alt="loading" src="./img/img5.png" src="image-placeholder-logo.svg">

src属性统一用一个占位图片,alt属性是在图像无法显示时的替代文本。src是自定义属性,用来保存实际的图片地址,可以通过 HTMLElement.dataset来访问。

脚本代码:

var container = document.querySelector('.container');

container.onscroll = function(){

 checkImgs();

}

function isInSight(el) {

 var sTop = container.scrollTop;

 var oHeight = container.offsetHeight;

 var oTop = el.offsetTop;

 return sTop + oHeight > oTop;

}

function checkImgs() {

 var imgs = document.querySelectorAll('.pic');

 Array.from(imgs).forEach(el => {

   if (isInSight(el)) {

     loadImg(el);

   }

 })

}

function loadImg(el) {

 var source = el.dataset.src;

 el.src = source;

}

checkImgs();

可以看出,页面加载时候,绑定外框的scroll事件,随着用户向下滚动鼠标,把img的src赋予新的值,网络重新发起请求,拉取图片。这里应该是有一些可以优化的地方,比如1、可以只监听向下滚动时候的事件,并设置延时(使用截流函数),防制多次调用回调函数。2、可以设一个标识符标识已经加载图片的index,当滚动条滚动时就不需要遍历所有的图片,只需要遍历未加载的图片即可。3、可以在计算的时候,增加偏移数据,提前加载图片,并使用淡入效果,提高流畅性。

另一种计算方法:

getClientRects()方法返回的一组矩形的集合, 即:是与该元素相关的CSS 边框集合 。包含边框的只读属性 lefttoprightbottom,单位为像素。除了 widthheight外的属性都是相对于视口的左上角位置而言的。

c209d079dcbe37cc1a6a3c1236a52574.png

这种条件下,假设 bound=el.getBoundingClientRect(),随着滚动条的向下滚动,bound.top会越来越小,也就是图片到可视区域顶部的距离越来越小,当 bound.top===clientHeight时,图片的上沿应该是位于可视区域下沿的位置的临界点,再滚动一点点,图片就会进入可视区域。也就是说,在 bound.top<=clientHeight时,图片是在可视区域内的。

function isInSight(el) {

 var bound = el.getBoundingClientRect();

 var clientHeight = window.innerHeight;

 return bound.top <= clientHeight;

}

进一步考虑:

以上监听scroll,并计算元素位置来实现惰性加载。当数据达到一定量的时候,事件绑定和循环位置计算会消耗大量的性能,每次调用 getBoundingClientRect() 都会强制浏览器 重新计算整个页面的布局 ,可能给你的网站造成相当大的闪烁。这种方式有些美中不足。

交叉观察器:

IntersectionObserver 就是为此而生的,它是HTML5新增的api,可以检测一个元素是否可见, IntersectionObserver能让你知道一个被观测的元素什么时候进入或离开浏览器的视口。

6c73fc7ac26d698563f783d106381687.gif

它兼容性有限,Chrome 51+(发布于 2016-05-25)Android 5+ (Chrome 56 发布于 2017-02-06)Edge 15 (2017-04-11)iOS 不支持

不过不用担心,WICG 提供了一个polyfill,可以兼容到以下版本:

d131356ffdfff135ba25c9fd54630b7b.png

它的用法也很简单,类似于rxjs中的observe:

var observe = new IntersectionObserver(callback, option);

IntersectionObserver是浏览器原生提供的构造函数,接受两个参数:callback是可见性变化时的回调函数,option是配置对象(可选)。返回一个观测实例observe,可以指定观测哪个DOM节点。

// 开始观察

observe.observe(document.getElementById('example'));

callback = function(entries){

 entries.forEach((entry) => {

   if (entry.isIntersecting) {

     //开始进入,交叉状态,在此处理图片逻辑。

   } else {

     //已完全进入或完全离开

   }

 });

}

// 停止观察

observe.unobserve(element);

// 关闭观察器

observe.disconnect();

entries是一个数组,每个成员都是一个 IntersectionObserverEntry对象。举例来说,如果同时有两个被观察的对象的可见性发生变化,entries数组就会有两个成员。isIntersecting,返回一个布尔值, 如果目标元素与交叉区域观察者对象的根相交,则返回 true 。如果返回 true,则描述了变换到交叉时的状态;如果返回 false, 那么可以由此判断,变换是从交叉状态到非交叉状态。IntersectionObserverEntry对象提供了很多有用的属性,比如target是被观察的目标元素,是一个 DOM 节点对象, intersectionRatio是目标元素的可见比例,即DOM节点的可见面积和总面积的比例,完全可见时为1,完全不可见时小于等于0,可以通过此属性设置图片的透明度,做成淡出的效果。

实现下拉无限滚动:

d32cffffb7510ad2a4ec027893c0d110.png

在页面底部有一个loading状态标签。一旦标签可见,就表示用户到达了页面底部,从而加载新的条目放在标签的前面。这样做的好处是,比监听scroll和计算节省了很多性能消耗,现有 IntersectionObserver可以很简单的应用。下面是实现方法:

var intersectionObserver = new IntersectionObserver(

 function (entries) {

   // 如果不可见,就返回

   if (entries[0].intersectionRatio <= 0) return;

   //在此加载新的数据

 });

intersectionObserver.observe(document.getElementById('loading'));

小结:

图片(不只有图片,主要是图片占用的资源最多最常见)惰性加载是一种网页优化技术。通过多种方案对比,使图片仅在浏览器当前视窗内出现时才加载该图片,达到减少首屏图片请求数,优化前端性能,提高用户体验。不管哪种方法,都有其自己的优势和劣势,掌握其中的原理,灵活应用才是最重要的。这对开发中遇到的问题及解决方法进行了总结,都是实战得来的经验,描述不清或者不对的地方,请多多指教。

2b1edf33007b1ffbe1d9230044907c9d.png

如果您觉得本文不错,

请点击文章底部广告,支持一下我啦!

▼原创系列推荐▼ 1. JavaScript 重温系列(22篇全) 2. ECMAScript 重温系列(10篇全) 3. JavaScript设计模式 重温系列(9篇全) 4. 正则 / 框架 / 算法等 重温系列(16篇全) 5.  Webpack4 入门手册(共 18 章)(上) 6.  Webpack4 入门手册(共 18 章)(下) 7.  59篇原创系列汇总

eda017cce7aa9c56504918fcf676c70c.png

76984ffc88a7d40924ae4981ae0248d3.png 点这,与大家一起分享本文吧~
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值