【JavaScript】使用纯JS实现多张图片的懒加载Lazy(附源码)

一、效果图如下

上面的效果图,效果需求如下

1、还没加载图片的时候,默认显示加载图片背景图

2、刚开始进入页面,自动加载第一屏幕的图片

3、下拉界面,当一张图片容器完全显露出屏幕,即刻加载图片,替换背景图

4、加载图片的时候,有渐进显示图片效果

二、难点

1)如何Ajax请求数据

2)如何动态将json数据绑定到html中。

3)如何通过对图片的定位计算,触发图片懒加载机制

4)加分项,显示图片时有渐现的过渡动画

三、前期知识点

1)Ajax相关知识,XMLHttpRequest对象,所有现代的浏览器都支持此对象。

2)innerHTML,数据绑定使用字符串拼接的方式

3)HTML DOM getAttribute() 方法,返回自定属性名的属性值(主要是用于返回自定义属性的属性值)

4)图片的 onload事件,当图片的src属性的属性值为正确(即能成功加载图片),才能触发图片的onload事件

四、难点逐一攻破

  1)如何Ajax请求数据

分四步走

// 1)首先创建一个Ajax对象
var xhr = new XMLHttpRequest;
// 2)打开我们需要请求的数据的那个文件地址
// URL地址后面加随机数目的:清除每一次请求数据时候(get请求)产生的缓存
// 因为每次访问的地址不一样,样浏览器就不会尝试缓存来自服务器的响应,读取本地缓存的数据。
xhr.open(‘get‘, ‘json/newsList.txt?‘ + Math.random(), false); // false代表同步
 // 3)监听请求的状态
xhr.onreadystatechange = function () {
    if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
        var val = xhr.responseText;
        jsonData = utils.jsonParse(val);
    }
}
// 4)发送请求
xhr.send(null);

  2)如何动态将json数据绑定到html中。

  字符串拼接的方式(数据绑定中最常用的方式),即通过使用innerHTML,对页面元素进行字符串拼接,再重新渲染到页面中

var str = "";
if (jsonData) {
    for (var i = 0, len = jsonData.length; i < len; i++) {
        var curData = jsonData[i];
        str += ‘<li>‘;
        str += ‘<div><img src="" trueImg="‘ + curData["img"] + ‘"></div>‘;
        str += ‘<div><h2>‘ + curData["title"] + ‘</h2>‘;
        str += ‘<p>‘ + curData["desc"] + ‘</p>‘;
        str += ‘</div>‘;
        str += ‘</li></div>‘;
    }
    news.innerHTML += str;
}    

  优势:数据绑定最常用的方式,因为浏览器只需要渲染一次(所有模板引擎数据绑定的原理就是字符串拼接,vue、angular、jade、kTemplate.js等等)
                   事先把内容拼接好,最后统一添加到页面中,只引发一次回流

  弊端:我们把新凭借的字符串添加到#ul1中,原有的三个li的鼠标滑过效果都消失了(原来标签绑定的事件都消失了)
                   原来,oUl.innerHTML的作用是把原来的标签以字符串的方式取出,原来作为标签的时候,对应事件绑定的东西已经没有了,然后进行字符串拼接,
                   但是,拼接完成之后,还是字符串!最后再把字符串统一添加到页面中,浏览器还需要把字符串渲染成为对应的标签

  3)如何通过对图片的定位计算,触发图片懒加载机制(最关键点)

  思路:

          A:代表图片距离屏幕顶部的距离 

//这里使用了utils工具类中的offset方法,具体实现看下面源码
var A = utils.offset(curImgPar).offsetTop + curImgPar.offsetHeight; 

          B:代表一屏幕距离+滚动条滚动距离

//这里使用了utils工具类中的win方法,具体实现看下面源码
var B = utils.win("clientHeight") + utils.win("scrollTop");

          A < B的时候,此时懒加载的默认图片才能完整显示出来,这个时候就需要触发图片懒加载

  4)加载图片的时候,有渐进显示图片效果

  思路,利用window.setInterval 方法,通过对当前图片的透明度属性(curImg.style.opacity) 从透明0开始到透明度1,变化总时间为500ms即可

// ->实现渐现效果
function fadeIn(curImg) {
    var duration = 500, // 总时间
    interval = 10, //10ms走一次
    target = 1; //总距离是1
    var step = (target / duration) * interval; //每一步的步长
    var timer = window.setInterval(function () {
        var curOp =  utils.getCss2SS(curImg, "opacity");
        if (curOp >= 1) {
            curImg.style.opacity = 1;
            window.clearInterval(timer);
            return
        }
        curOp += step;
        curImg.style.opacity = curOp;
    }, interval);
}

 

五、完整代码

        1)main.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!--做移动端响应式布局页面,都需要加下面的meta-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!--meta:vp+tap一键生成-->
    <title>多张图片的延迟加载</title>
    <style type="text/css">
        * {
            margin: 0;
            padding: 0;
            font-family: "Microsoft Sans Serif";
            font-size: 14px;
        }
        ul, li {
            list-style: none;
        }
        img {
            display: block;
            border: none;
        }
        .news {
            padding: 10px;
        }
        .news li {
            position: relative;
            height: 60px;
            padding: 10px 0;
            border-bottom: 1px solid #eee;
        }
        .news li > div:first-child {   /*意思是,li下面的子div,中的第一个*/
            position: absolute;
            top: 10px;
            left: 0;
            width: 75px;
            height: 60px;
            background: url("./img/loading.PNG") no-repeat center center #e1e1e1;
            background-size: 100% 100%;
        }
        /*移动端布局,最外层容器是不设置宽高的*/

        .news li > div:first-child img {
            display: none;
            width: 100%;
            height: 100%;
            opacity: 0;  /*这里设置为0的目的是,实现渐进的效果,后面的fadeIn函数,作用就是让图片透明都从0变成1*/
        }

        .news li > div:nth-child(2) {
            height: 60px;
            margin-left: 80px;
        }
        .news li > div:nth-child(2) h2 {
            height: 20px;
            line-height: 20px;
            /*实现文字超出一行自动裁切*/
            overflow: hidden;
            text-overflow: ellipsis; /*超出部分省略号显示*/
            white-space: nowrap; /*强制不换行*/
        }
        .news li > div:nth-child(2) p {
            line-height: 20px;
            font-size: 12px;
            color: #616161;
        }
    </style>
</head>
<body>
    <ul id="news" class="news">
        <!--<li>-->
            <!--<div>-->
                <!--<img src="./img/new1.PNG" >-->
            <!--</div>-->
            <!--<div>-->
                <!--<h2>香港四大家族往事,香港四大家族往事,香港四大家族往事</h2>-->
                <!--<p>香港四大家族往事:李嘉诚为郑裕彤扶灵香港四大家族往事:李嘉诚为郑裕彤扶灵</p>-->
            <!--</div>-->
        <!--</li>-->
    </ul>

<script type="text/javascript" src="./tool/utils.js"></script>
<script type="text/javascript">
    var news = document.getElementById("news"),
        imgList = news.getElementsByTagName("img");

    // 1、获取需要绑定的数据(通过Ajax)
    var jsonData = null;
    ~function () {
        // 1)首先创建一个Ajax对象
        var xhr = new XMLHttpRequest;
        // 2)打开我们需要请求的数据的那个文件地址
        // URL地址后面加随机数目的:清除每一次请求数据时候(get请求)产生的缓存
        // 因为每次访问的地址不一样,样浏览器就不会尝试缓存来自服务器的响应,读取本地缓存的数据。
        xhr.open(‘get‘, ‘json/newsList.txt?‘ + Math.random(), false); // false代表同步
        // 3)监听请求的状态
        xhr.onreadystatechange = function () {
            if (xhr.readyState === 4 && /^2\d{2}$/.test(xhr.status)) {
                var val = xhr.responseText;
                jsonData = utils.jsonParse(val);
            }
        }
        // 4)发送请求
        xhr.send(null);
    }();
    console.log(jsonData);

    // 2、数据绑定(使用字符串拼接的方式)
    ~function () {
        var str = "";
        if (jsonData) {
            for (var i = 0, len = jsonData.length; i < len; i++) {
                var curData = jsonData[i];
                str += ‘<li>‘;
                str += ‘<div><img src="" trueImg="‘ + curData["img"] + ‘"></div>‘;
                str += ‘<div><h2>‘ + curData["title"] + ‘</h2>‘;
                str += ‘<p>‘ + curData["desc"] + ‘</p>‘;
                str += ‘</div>‘;
                str += ‘</li></div>‘;
            }
            news.innerHTML += str;
        }
    }();

    // 3、图片延迟加载
    // ->首先实现单张图片的延时加载
    function lazyImg(curImg) {
        var oImg = new Image;
        oImg.src = curImg.getAttribute("trueImg");
        oImg.onload = function() {
            curImg.src = this.src;
            curImg.style.display = "block";
            fadeIn(curImg);
            oImg = null;
        }
        curImg.isLoad = true;
    }

    // -> 循环处理每一张图片
    function handleAllImg() {
        for (var i = 0, len = imgList.length; i < len; i++) {
            var curImg = imgList[i];
            if (curImg.isLoad) { // 当前图片处理过的话,就不需重新进行处理
                continue;
            }

            // ->只有当A小于B的时候再进行处理
//          var A = utils.offset(curImg).top + curImg.offsetHeight; // 这里A不能这么计算,因为此时图片是隐藏的,没有图片,他的offsetHeight当让也是为0
                                                                      // 如果我要的到图片的A值,我们可以通过拿到他父节点的容器就行了,哈哈
            var curImgPar = curImg.parentNode,
                A = utils.offset(curImgPar).offsetTop + curImgPar.offsetHeight,
                B = utils.win("clientHeight") + utils.win("scrollTop");
            if (A < B) {
                lazyImg(curImg);
            }
        }
    }

    // ->实现渐现效果
    function fadeIn(curImg) {
        var duration = 500, // 总时间
            interval = 10, //10ms走一次
            target = 1; //总距离是1
        var step = (target / duration) * interval; //每一步的步长
        var timer = window.setInterval(function () {
            var curOp =  utils.getCss2SS(curImg, "opacity");
            if (curOp >= 1) {
                  curImg.style.opacity = 1;
                  window.clearInterval(timer);
                  return
            }
            curOp += step;
            curImg.style.opacity = curOp;
        }, interval);
    }

    // 4、开始的时候(过500ms)加载1屏幕的图片,当滚动条滚动的时候,加载其他图片
    window.setTimeout(handleAllImg, 500);
    window.onscroll = handleAllImg;

</script>
</body>
</html>

  

  2)utils.js

// 为了与全局变量冲突,我们使用单例模式
var utils = {
  // jsonParse: 把JSON格式的字符串转化为JSON格式的对象
  jsonParse: function (str) {
      var val = null;
       try {
          val = JSON.parse(str);
      } catch (e) {
          val = eval(‘(‘ + str + ‘)‘);
      }
      return val;
  },

  getCss2SS : function(curEle, attr) {
      var val = null, reg = null;
      if (‘getComputedStyle‘ in window) {
          val = window.getComputedStyle(curEle, null)[attr];
      } else {
          if (attr === ‘opacity‘) {
              val = curEle.currentStyle[attr]; // ->返回 alpha(opacity=10)
              reg = /^alpha\(opacity=(\d+(?:\.\d+)?)\)$/i;  //  获取10这个数字
              val = reg.test(val)?reg.exec(val)[1]/100:1  // 超厉害,test与exec一起使用!!!
          }
          val = curEle.currentStyle[attr];
      }
      reg = /^-?\d+(\.\d+)?(px|pt|rem|em)?$/i; //匹配的情况:纯数值或者带单位的数值
      return reg.test(val) ? parseFloat(val) : val;
  },

  offset : function(curEle) {
      var totalLeft = null,
          totalTop = null,
          par = curEle.offsetParent;
      // 首先把自己本身的进行累加
      totalLeft += curEle.offsetLeft;
      totalTop += curEle.offsetTop;

      while (par) {
          if (navigator.userAgent.indexOf("MSIE 8.0") === -1) {
              // 累加父级参照物边框
              totalTop += par.clientTop;
              totalLeft += par.clientLeft;
          }
          // 累加父级参照物本身的偏移
          totalTop += par.offsetTop;
          totalLeft += par.offsetLeft;
          par = par.offsetParent;
      }
      console.log(‘offsetTop: ‘ + totalTop + ‘, offsetLeft: ‘ + totalLeft);
      var result = {};
      result.offsetTop = totalTop;
      result.offsetLeft = totalLeft;
      return result;
  },

  win : function(attr, value) {
      if (value === undefined) {
          return document.documentElement[attr] || document.body[attr];
      }
      document.documentElement[attr] = value;
      document.body[attr] = value;
  }
};

  3、json文件

[{"img":"./img/new1.PNG", "title": "1网络强国战略与“十三五”十四大战略", "desc": "1互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"},
 {"img":"./img/new2.PNG", "title": "2网络强国战略与“十三五”十四大战略", "desc": "2互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"},
 {"img":"./img/new3.PNG", "title": "3网络强国战略与“十三五”十四大战略", "desc": "3互联网是二十世纪人类最大的发明,互联网是二十世纪人类最大的发明"}
]

原文地址:https://www.cnblogs.com/pengshengguang/p/11669176.html

时间: 2024-12-09 23:44:33

【JavaScript】使用纯JS实现多张图片的懒加载Lazy(附源码)的相关文章

swiper.js 多图片页面的懒加载lazyLoading

swiper.js官网:http://www.swiper.com.cn/api/Images/2015/0308/213.html 设为true开启图片延迟加载,使preloadImages无效.需要将图片img标签的src改写成data-src,并且增加类名swiper-lazy.背景图的延迟加载则增加属性data-background(3.0.7开始启用). lazyLoadingInPrevNextAmount 设置在延迟加载图片时提前多少个slide.个数不可少于slidesPerVi

arcgis api 4.x for js 集成 Echarts4 实现模拟迁徙图效果(附源码下载)

前言 关于本篇功能实现用到的 api 涉及类看不懂的,请参照 esri 官网的 arcgis api 4.x for js:esri 官网 api,里面详细的介绍 arcgis api 4.x 各个类的介绍,还有就是在线例子:esri 官网在线例子,这个也是学习 arcgis api 4.x 的好素材. arcgis api 4.x for js 集成 echarts 实现迁徙图效果的关键问题在于 echarts 坐标系以及 arcgis 坐标系不一致,因此要进行 echarts坐标系与 arc

纯js懒加载,java后台举例

? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 function getElementsByClassName(str,root,tag){        if(root){            root = type

js效果笔记:怎样实现图片的懒加载以及jquery.lazyload.js的使用

在项目中有时候会用到图片的延迟加载,那么延迟加载的好处是啥呢? 我觉得主要包括两点吧,第一是在包含很多大图片长页面中延迟加载图片可以加快页面加载速度:第二是帮助降低服务器负担. 下面介绍一下常用的延迟加载插件jquery.lazyload.js以及怎样实现一个延迟加载的插件. 一:jquery.lazyload.js插件 lazyload是jQuery写的延迟加载插件,在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动到它们所在的位置. 这与图片预加载的处理方式正好是相反的. 实现原理 首

jQuery延迟加载(懒加载)插件 – jquery.lazyload.js

Lazy Load 是一个用 JavaScript 编写的 jQuery 插件. 它可以延迟加载长页面中的图片. 在浏览器可视区域外的图片不会被载入, 直到用户将页面滚动到它们所在的位置. 这与图片预加载的处理方式正好是相反的.在包含很多大图片长页面中延迟加载图片可以加快页面加载速度. 浏览器将会在加载可见图片之后即进入就绪状态. 在某些情况下还可以帮助降低服务器负担. Demo页面: 基本选项 淡入效果 对不支持JavaScript浏览器的降级处理 水平滚动 容器内水平滚动 容器内垂直滚动 页

Javascript图片的懒加载与预加载

1. 缓载.预载的概念 这些技术不仅限于图片加载,但我们首先讨论最常用的图片加载. 缓载:延迟加载图片或符合某些条件时才加载某些图片. 预载:提前加载图片,当用户需要查看时可直接从本地缓存中渲染. 两种技术的本质:两者的行为是相反的,一个是提前加载,一个是迟缓甚至不加载.缓载对服务器前端有一定的缓解压力作用,预载则会增加服务器前端压力. 2. 缓载的意义与实现 缓载的主要目的是作为服务器前端的优化,减少请求数或延迟请求数. 主要体现在三种模式上: 第一种是纯粹的延迟加载,使用setTimeOut

原生JavaScript实现懒加载

源码工程下载地址:https://github.com/blff122620/jsLibary/lazyLoad.html 实现原理就是通过scroll事件判断元素是否已经进入viewport 导入 lazyLoad.js 使用 inViewPort(item)即可 判断item是否在视口里,然后继续进行自己的逻辑就行了 <!DOCTYPE html> <html lang="zh"> <head> <meta charset="UT

抛砖引玉:大型网站性能优化之Javascript异步懒加载技术

懒加载技术是现在许多大型网站的都使用的提高网站性能的方式,它的核心思想是当用户想看页面某个区域时,再加载该区域的数据.这在一定程度上减轻了服务器端的压力,也加快了页面的呈现速度. 其实国内很多网站都用到了懒加载技术,比如国内两个大型电商网站的页面都运用到了这项技术: 天猫首页: 京东商品列表页: 最近在学习时,自己写了一个带懒加载功能的电影列表展示页,大家可以先看下页面效果: http://f81236211.w4w7.tumm.top/lazyload/ 然后自己在页面底部写了一个分页功能,页

原生javascript代码懒加载

1.先定义需要懒加载的样式: class="lazyload" 2.设置初始透明度为0.1: .lazyload{ filter: Alpha(opacity=10); -moz-opacity:0.1; opacity:0.1; } 3.把真正需要加载的真实地址放在data-src属性中: src="懒加载图片.png" data-src="真实图片"; 4. 前端开发周大伟同学JavaScript代码编写: function lazyload