欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

jQuery懒加载实现和源码

程序员文章站 2022-07-02 16:10:29
...


为什么浏览器需要懒加载 :

  1. 假设情况 : 页面之中有一千张图片,有一些是在显示区域内的,有一些是在显示区域外的;
    因为浏览器加载图片是没有先后限制的,统一发起请求,谁先加载完就先渲染谁,资源分配随机, 会导致不好的用户体验。
  2. 懒加载: 让浏览器把性能放在显示区域内去进行数据的加载。

第一种

HTML结构

基于jQuery实现的懒加载
注意:图片的 src 需要修改为 data-lazy-src

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  img {
    display: block;
    margin-bottom: 200px;
  }
</style>

<body>
  <img data-lazy-src="./images/P_000.jpg" alt="">
  <img data-lazy-src="./images/P_001.jpg" alt="">
  <img data-lazy-src="./images/P_002.jpg" alt="">
  <img data-lazy-src="./images/P_003.jpg" alt="">
  <img data-lazy-src="./images/P_004.jpg" alt="">
  <img data-lazy-src="./images/P_005.jpg" alt="">
  <img data-lazy-src="./images/P_006.jpg" alt="">
  <img data-lazy-src="./images/P_007.jpg" alt="">
  <img data-lazy-src="./images/P_008.jpg" alt="">
  <img data-lazy-src="./images/P_009.jpg" alt="">
  <img data-lazy-src="./images/P_010.jpg" alt="">
  <img data-lazy-src="./images/P_011.jpg" alt="">
  <img data-lazy-src="./images/P_012.jpg" alt="">
  <img data-lazy-src="./images/P_013.jpg" alt="">
  <img data-lazy-src="./images/P_014.jpg" alt="">
  <img data-lazy-src="./images/P_015.jpg" alt="">
  <img data-lazy-src="./images/P_016.jpg" alt="">
  <img data-lazy-src="./images/P_017.jpg" alt="">
  <img data-lazy-src="./images/P_018.jpg" alt="">
  <img data-lazy-src="./images/P_019.jpg" alt="">
  
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
  <script src="./js/EasyLazyload.min.js"></script>
  <script>
    //调用函数
    lazyLoadInit({
      showTime: 1000,
      onLoadBackEnd: function (i, e) {
        console.log("onLoadBackEnd:" + i);
      },
      onLoadBackStart: function (i, e) {
        console.log("onLoadBackStart:" + i);
      }
    });
  </script>
</body>

</html>

jQuery懒加载实现和源码

EasyLazyload.min.js 文件

! function (t) {
  function o(o, a, i) {
    var n, c, e = new Image;
    return e.src = o, e.onload = function () {
      a(e.width, e.height), r.onLoadBackStart(i, t("img[data-lazy-src]:eq(" + i + ")"))
    }, [n, c]
  }

  function a(a, n) {
    var c = l.eq(a).attr("data-lazy-src");
    o(c, function () {
      try {
        i(t("img[data-lazy-src]:eq(" + a + ")"), a, n)
      } catch (t) {}
    }, a)
  }

  function i(o, a, i) {
    if (!o.attr("data-comp")) {
      o.css("visibility", "hidden"), o.attr("src", o.attr("data-lazy-src"));
      var c = o.width(),
        e = o.height(),
        d = o.offset().top,
        f = o.offset().left;
      o.css("visibility", "visible"), t("body").append("<div class='meng-lazy-div" + a + "' style='background-color: " + r.coverColor + ";position:absolute;width:" + c + "px;height:" + e + "px;top:" + d + "px;left:" + f + "px;z-index:500'>" + r.coverDiv + "</div>"), n(a, i, o), o.attr("data-comp", "true")
    }
  }

  function n(o, a, i) {
    t(".meng-lazy-div" + o).animate({
      opacity: "0"
    }, r.showTime, function () {
      t(this).remove(), r.onLoadBackEnd(o, i), a()
    })
  }

  function c() {
    var o = t(document).scrollTop(),
      i = [];
    l.each(function (a) {
      var n = t(this);
      n.attr("data-comp") || n.offset().top - o + r.offsetTopm >= 0 && n.offset().top - o < s + r.offsetBottom && i.push(a)
    }), 0 != i.length && a(i[0], function () {
      c()
    })
  }

  function e() {
    c()
  }

  function d(o) {
    r = t.extend(r, o), l.each(function () {
      var o = t(this).attr("data-lazy-src");
      f.push(o), t(this).attr("src", A)
    }), e(), window.onscroll = function () {
      e()
    }
  }
  var r = {
      coverColor: "#dfdfdf",
      coverDiv: "",
      showTime: 300,
      offsetBottom: 0,
      offsetTopm: 50,
      onLoadBackEnd: function (t, o) {},
      onLoadBackStart: function (t, o) {}
    },
    f = [],
    s = t(window).height(),
    l = (t(window).width(), t("img[data-lazy-src]")),
    A = "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==";
  window.lazyLoadInit = d
}($);

对于源码还得深究啊

第二种(推荐用这种)

注意点:
1、必须给img设置默认高度,不然懒加载无效。
2、修改 img 里面属性 class=“lazy” data-original= “ ”

HTML结构

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<style>
  img {
    margin-bottom: 200px;
    /* 注意:这个懒加载一定要给img默认高度 不然懒加载无效*/
    height: 300px;
    margin-right: 400px;
  }
</style>

<body>
  <img class="lazy" data-original="./images/P_000.jpg" alt="">
  <img class="lazy" data-original="./images/P_001.jpg" alt="">
  <img class="lazy" data-original="./images/P_002.jpg" alt="">
  <img class="lazy" data-original="./images/P_003.jpg" alt="">
  <img class="lazy" data-original="./images/P_004.jpg" alt="">
  <img class="lazy" data-original="./images/P_005.jpg" alt="">
  <img class="lazy" data-original="./images/P_006.jpg" alt="">
  <img class="lazy" data-original="./images/P_007.jpg" alt="">
  <img class="lazy" data-original="./images/P_008.jpg" alt="">
  <img class="lazy" data-original="./images/P_009.jpg" alt="">
  <img class="lazy" data-original="./images/P_010.jpg" alt="">
  <img class="lazy" data-original="./images/P_011.jpg" alt="">
  <img class="lazy" data-original="./images/P_012.jpg" alt="">
  <img class="lazy" data-original="./images/P_013.jpg" alt="">
  <img class="lazy" data-original="./images/P_014.jpg" alt="">
  <img class="lazy" data-original="./images/P_015.jpg" alt="">
  <img class="lazy" data-original="./images/P_016.jpg" alt="">
  <img class="lazy" data-original="./images/P_017.jpg" alt="">
  <img class="lazy" data-original="./images/P_018.jpg" alt="">
  <img class="lazy" data-original="./images/P_019.jpg" alt="">

  <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.js"></script>
  <script src="./js/jquery.lazyload.js"></script>
  <script>
    // 为什么浏览器需要懒加载 :
    // 1. 假设情况 : 页面之中有一千张图片,有一些是在显示区域内的,有一些是在显示区域外的;
    // 因为浏览器加载图片是没有先后限制的,统一发起请求,谁先加载完就先渲染谁,资源分配随机, 会导致不好的用户体验。
    // 2. 懒加载: 让浏览器把性能放在显示区域内去进行数据的加载;
    // 使用懒加载插件即可;
    $("img.lazy").lazyload({ effect: "fadeIn" });

    // 注意事项 : 图片一定要设置默认高度否则懒加载无效;
  </script>
</body>

</html>

jquery.lazyload.js 文件

/*
 * Lazy Load - jQuery plugin for lazy loading images
 *
 * Copyright (c) 2007-2013 Mika Tuupola
 *
 * Licensed under the MIT license:
 *   http://www.opensource.org/licenses/mit-license.php
 *
 * Project home:
 *   http://www.appelsiini.net/projects/lazyload
 *
 * Version:  1.9.3
 *
 */

(function ($, window, document, undefined) {
  var $window = $(window);

  $.fn.lazyload = function (options) {
    var elements = this;
    var $container;
    var settings = {
      threshold: 0,
      failure_limit: 0,
      event: "scroll",
      effect: "show",
      container: window,
      data_attribute: "original",
      skip_invisible: true,
      appear: null,
      load: null,
      placeholder: "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAANSURBVBhXYzh8+PB/AAffA0nNPuCLAAAAAElFTkSuQmCC"
    };

    function update() {
      var counter = 0;
      elements.each(function () {
        var $this = $(this);
        if (settings.skip_invisible && !$this.is(":visible")) {
          return;
        }
        if ($.abovethetop(this, settings) ||
          $.leftofbegin(this, settings)) {
          /* Nothing. */
        } else if (!$.belowthefold(this, settings) &&
          !$.rightoffold(this, settings)) {
          $this.trigger("appear");
          /* if we found an image we'll load, reset the counter */
          counter = 0;
        } else {
          if (++counter > settings.failure_limit) {
            return false;
          }
        }
      });
    }

    if (options) {
      /* Maintain BC for a couple of versions. */
      if (undefined !== options.failurelimit) {
        options.failure_limit = options.failurelimit;
        delete options.failurelimit;
      }
      if (undefined !== options.effectspeed) {
        options.effect_speed = options.effectspeed;
        delete options.effectspeed;
      }

      $.extend(settings, options);
    }

    /* Cache container as jQuery as object. */
    $container = (settings.container === undefined ||
      settings.container === window) ? $window : $(settings.container);

    /* Fire one scroll event per scroll. Not one scroll event per image. */
    if (0 === settings.event.indexOf("scroll")) {
      $container.bind(settings.event, function () {
        return update();
      });
    }

    this.each(function () {
      var self = this;
      var $self = $(self);

      self.loaded = false;

      /* If no src attribute given use data:uri. */
      if ($self.attr("src") === undefined || $self.attr("src") === false) {
        if ($self.is("img")) {
          $self.attr("src", settings.placeholder);
        }
      }

      /* When appear is triggered load original image. */
      $self.one("appear", function () {
        if (!this.loaded) {
          if (settings.appear) {
            var elements_left = elements.length;
            settings.appear.call(self, elements_left, settings);
          }
          $("<img />")
            .bind("load", function () {

              var original = $self.attr("data-" + settings.data_attribute);
              $self.hide();
              if ($self.is("img")) {
                $self.attr("src", original);
              } else {
                $self.css("background-image", "url('" + original + "')");
              }
              $self[settings.effect](settings.effect_speed);

              self.loaded = true;

              /* Remove image from array so it is not looped next time. */
              var temp = $.grep(elements, function (element) {
                return !element.loaded;
              });
              elements = $(temp);

              if (settings.load) {
                var elements_left = elements.length;
                settings.load.call(self, elements_left, settings);
              }
            })
            .attr("src", $self.attr("data-" + settings.data_attribute));
        }
      });

      /* When wanted event is triggered load original image */
      /* by triggering appear.                              */
      if (0 !== settings.event.indexOf("scroll")) {
        $self.bind(settings.event, function () {
          if (!self.loaded) {
            $self.trigger("appear");
          }
        });
      }
    });

    /* Check if something appears when window is resized. */
    $window.bind("resize", function () {
      update();
    });

    /* With IOS5 force loading images when navigating with back button. */
    /* Non optimal workaround. */
    if ((/(?:iphone|ipod|ipad).*os 5/gi).test(navigator.appVersion)) {
      $window.bind("pageshow", function (event) {
        if (event.originalEvent && event.originalEvent.persisted) {
          elements.each(function () {
            $(this).trigger("appear");
          });
        }
      });
    }

    /* Force initial check if images should appear. */
    $(document).ready(function () {
      update();
    });
    return this;
  };

  /* Convenience methods in jQuery namespace.           */
  /* Use as  $.belowthefold(element, {threshold : 100, container : window}) */

  $.belowthefold = function (element, settings) {
    var fold;

    if (settings.container === undefined || settings.container === window) {
      fold = (window.innerHeight ? window.innerHeight : $window.height()) + $window.scrollTop();
    } else {
      fold = $(settings.container).offset().top + $(settings.container).height();
    }

    return fold <= $(element).offset().top - settings.threshold;
  };

  $.rightoffold = function (element, settings) {
    var fold;

    if (settings.container === undefined || settings.container === window) {
      fold = $window.width() + $window.scrollLeft();
    } else {
      fold = $(settings.container).offset().left + $(settings.container).width();
    }

    return fold <= $(element).offset().left - settings.threshold;
  };

  $.abovethetop = function (element, settings) {
    var fold;

    if (settings.container === undefined || settings.container === window) {
      fold = $window.scrollTop();
    } else {
      fold = $(settings.container).offset().top;
    }

    return fold >= $(element).offset().top + settings.threshold + $(element).height();
  };

  $.leftofbegin = function (element, settings) {
    var fold;

    if (settings.container === undefined || settings.container === window) {
      fold = $window.scrollLeft();
    } else {
      fold = $(settings.container).offset().left;
    }

    return fold >= $(element).offset().left + settings.threshold + $(element).width();
  };

  $.inviewport = function (element, settings) {
    return !$.rightoffold(element, settings) && !$.leftofbegin(element, settings) &&
      !$.belowthefold(element, settings) && !$.abovethetop(element, settings);
  };

  /* Custom selectors for your convenience.   */
  /* Use as $("img:below-the-fold").something() or */
  /* $("img").filter(":below-the-fold").something() which is faster */

  $.extend($.expr[":"], {
    "below-the-fold": function (a) {
      return $.belowthefold(a, {
        threshold: 0
      });
    },
    "above-the-top": function (a) {
      return !$.belowthefold(a, {
        threshold: 0
      });
    },
    "right-of-screen": function (a) {
      return $.rightoffold(a, {
        threshold: 0
      });
    },
    "left-of-screen": function (a) {
      return !$.rightoffold(a, {
        threshold: 0
      });
    },
    "in-viewport": function (a) {
      return $.inviewport(a, {
        threshold: 0
      });
    },
    /* Maintain BC for couple of versions. */
    "above-the-fold": function (a) {
      return !$.belowthefold(a, {
        threshold: 0
      });
    },
    "right-of-fold": function (a) {
      return $.rightoffold(a, {
        threshold: 0
      });
    },
    "left-of-fold": function (a) {
      return !$.rightoffold(a, {
        threshold: 0
      });
    }
  });
})(jQuery, window, document);