天天看点

一张图片引发的思考---懒加载

最近在做一个图片list预览组件,在一组图片list 中点击其中一张图片 可以放大 缩小,旋转、下载等功能。 但是list 中可能很多图片,如果首次打开这个页面, 每个图片都加载,浪费服务器资源,也给页面渲染带来极大的性能损耗。(http请求是宝贵的);

一.如何做到懒加载 也叫按需加载?

懒加载原理 ,初始化时候给页面的img 标签的src属性 ,默认赋值loading图片,增加一个 自定义的data-src 属性 ,存放真实的图片地址,遍历判断img 标签在视口中 , 把data-src 中的真实地址,赋值给src属性 ,加载真实的图片。

二.如何判断img 标签已经在视口

原始的转化方式 :

1. 

document.documentElement.clientHeight

获取屏幕可视窗口高度 ,

2.el.offsetTop 获取元素距离文档顶部的 距离,

3.document.documentElement.scrollTop 文档向下滚动的距离。 如下图 当 ② - ① < ③    说明图片已经在视口内部。可以加载。

一张图片引发的思考---懒加载

现成的API    getBoundingClientRect  :

浏览器提供 Element.getBoundingClientRect() 方法来获取元素的大小以及位置,包括 矩形 盒子的大小,top 、left、bottom  right 。

如下图。这些位置信息是相对视口 左上角为原点返回的数值。什么情况下是img 进入视口的呢?  假设,我们获取img 相对视口的信息 const  coordinateData= el.getBoundingClientRect() ,  const clientHeight = window.innerHeight , 很容易 coordinateData.top ===clientHeight 的 时候 ,img 将要进入视口。ok 

一张图片引发的思考---懒加载
function isInViewport(el){
try{
   const {top,left,bottom,right}= el.getBoundingClientRect();
  const height= window.innerHeight;
  const width = window.innerWidth;
  const yInView = top<height&&bottom>0;
  const xInView = left<width&&right>0;
  return yInView&&xInView;
}catch(err){}
}

function getImgs(){
const imgs=  document.querySelectorAll('.photolist') ;
 Array.from(imgs).forEach(item=>{
    if (isInViewport(item)){
     if (item['data-isLoaded'])return;
     item.src = item['data-src'];
     item['data-isLoaded'] = true;
     }
})
}

           

上面的 代码 还为已经加载的img 标签添加了自定义属性,  如果该标签已经加载过图片, 以后的遍历就不会重新加载。

这里还可以优化下, 在页面滚动的时候 ,一直去访问dom 执行操作,对页面性能是很大的损耗。 这里我们可以写一个节流函数,

具体解释看这里;

function throttle(fn,delay){
   let deferTimer , last;
    return function (args){
      const context = this;
      const now = new Date();
      const _args = arguments;
   if(last&&now<last + delay){
     if(!deferTimer){
   deferTimer = setTimeout(()=>{
       fn.apply(context,_args);
       last=now;
      clearTimeout(deferTimer)
     },last+delay-now);
   }
} else {
    fn.apply(context,_args);
    last=now;

}
    }

}
           

window.addEventListener('scroll',()=>{

throttle(getImgs(),500ms)

});

继续阅读