每天看一片代码系列(四):layzr.js,处理图片懒加载的库

所谓图片的懒加载,即只有当图片处于或者接近于当前视窗时才开始加载图片。该库的使用方法非常简单:

var layzr = new Layzr({
  attr: ‘data-layzr‘,   // attr和retinaAttr必须至少有一个,用于指定对应的图片
  retinaAttr: ‘data-layzr-retina‘, // 一般对应的图像比attr要高清
  threshold: 0,  // 距离视窗的距离为多少时开始加载
  callback: null  // 回调函数
});

代码解析

首先是包装成为umd的方式:

(function(root, factory) {
  if(typeof define === ‘function‘ && define.amd) {
    define([], factory); // 使用amd定义一个模块,依赖为空
  } else if(typeof exports === ‘object‘) {
    module.exports = factory(); // cmd方式,暴露返回值
  } else {
    root.Layzr = factory(); // 浏览器环境下
  }
}(this, function() {

})

接下来是构造函数:

  function Layzr( options ) {
    this._lastScroll = 0;
    this._ticking = false;

    // 参数
    this._optionsAttr = options.attr || ‘data-layzr‘;
    this._optionsAttrRetina = options.retinaAttr || ‘data-layzr-retina‘;
    this._optionsThreshold = options.threshold || 0;
    this._optionsCallback = options.callback || null;

    // 获取合适的属性
    this._retina = window.devicePixelRatio > 1;
    this._imgAttr = this._retina ? this._optionsAttrRetina : this._optionsAttr;

    // 所有的图像集合
    this._images = document.getElementsByTagName(‘img‘);

    // call to create
    this._create();
  }

create和destory函数:

Layzr.prototype._create = function() {
    // 记录初始的scroll位置
    this._requestScroll();

    // scroll和resize对应的事件处理函数
    window.addEventListener(‘scroll‘, this._requestScroll.bind(this), false);
    window.addEventListener(‘resize‘, this._requestScroll.bind(this), false);
  }

  Layzr.prototype._destroy = function() {
    // unbind事件
    window.removeEventListener(‘scroll‘, this._requestScroll.bind(this), false);
    window.removeEventListener(‘resize‘, this._requestScroll.bind(this), false);
  }

requestScroll的具体实现:

  Layzr.prototype._requestScroll = function() {
    this._lastScroll = window.scrollY || window.pageYOffset; // 垂直方向上的滚动距离
    this._requestTick();
  }

  Layzr.prototype._requestTick = function() {
    if(!this._ticking) {
     // requestAnimationFrame主要用于绘制图像,通过优化提高效率
     // 这里用于每次滚动都调用update
      requestAnimationFrame(this.update.bind(this));
      this._ticking = true;
    }
  }

  Layzr.prototype.update = function() {
    var imagesLength = this._images.length;
    for(var i = 0; i < imagesLength; i++) {
      var image = this._images[i];

     // 如果当前的图片有设定的属性
      if(image.hasAttribute(this._imgAttr) || image.hasAttribute(this._optionsAttr)) {
        // 且已经处于视窗中
        if(this._inViewport(image)) {
          // 加载这个图片
          this.reveal(image);
        }
      }
    }

    // allow for more animation frames
    this._ticking = false;
  }

是否在视窗中的判断:

  Layzr.prototype._inViewport = function( imageNode ) {
    // 视窗的顶部和底部
    var viewportTop = this._lastScroll;
    var viewportBottom = viewportTop + window.innerHeight;

    // 图像的顶部和底部
    var elementTop = this._getOffset(imageNode);
    var elementBottom = elementTop + imageNode.offsetHeight;

    // 计算threshold对应的像素
    var threshold = (this._optionsThreshold / 100) * window.innerHeight;

    // 是否在这个区间中
    return elementBottom >= viewportTop - threshold && elementBottom <= viewportBottom + threshold;
  }

展示图像的实现:

Layzr.prototype.reveal = function( imageNode ) {
    // 获取图像的src
    var source = imageNode.getAttribute(this._imgAttr) || imageNode.getAttribute(this._optionsAttr);

    // 去除设置的属性
    imageNode.removeAttribute(this._optionsAttr);
    imageNode.removeAttribute(this._optionsAttrRetina);

    //设置src
    if(source) {
      imageNode.setAttribute(‘src‘, source);

      // 调用callback
      if(typeof this._optionsCallback === ‘function‘) {
        this._optionsCallback.call(imageNode);
      }
    }
  }

总结

  1. 基本流程: 滚动--》记录位置--》遍历图片--》判断是否在视窗中--》从属性中获取并设置图像src--》调用回调函数
  2. window.scrollY || window.pageYOffset 用于获取垂直滚动的距离
  3. 视窗高度:window.innerHeight,元素高度: node.offsetHeight
  4. 获取元素相对于doucment顶部的距离:http://stackoverflow.com/questions/5598743/finding-elements-position-relative-to-the-document
时间: 2024-12-16 17:33:47

每天看一片代码系列(四):layzr.js,处理图片懒加载的库的相关文章

使用Webpack的代码拆分在Vue中进行懒加载

参考学习:https://alexjover.com/blog/lazy-load-in-vue-using-webpack-s-code-splitting/ 学习文案:https://webpack.docschina.org/guides/lazy-loading/ 原文地址:https://www.cnblogs.com/nayek/p/12123639.html

webpack4 系列教程(七): SCSS提取和懒加载

教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步>>> (原文)webpack4 系列教程(七): SCSS 提取和懒加载. 个人技术小站: https://godbmw.com 有空就来看看, 我一直都在 本节课讲解在webpack v4中的 SCSS 提取和懒加载.值得一提的是,v4和v3在 Scss 的懒加载上的处理方法有着巨大差别. >>> 本节课源码 >>> 所有课程源码 1. 准备工作 关于 SCSS 处理的基础,请参考w

webpack4 系列教程(四): 单页面解决方案--代码分割和懒加载

本节课讲解webpack4打包单页应用过程中的代码分割和代码懒加载.不同于多页面应用的提取公共代码,单页面的代码分割和懒加载不是通过webpack配置来实现的,而是通过webpack的写法和内置函数实现的. 目前webpack针对此项功能提供 2 种函数: import(): 引入并且自动执行相关 js 代码 require.ensure(): 引入但需要手动执行相关 js 代码 本文将会进行逐一讲解. >>> 本节课源码 >>> 所有课程源码 1. 准备工作 此次代码

代码: 两列图片瀑布流(一次后台取数据,图片懒加载。下拉后分批显示图片。图片高度未知,当图片onload后才显示容器)

代码: 两列图片瀑布流(一次后台取数据,无ajax,图片懒加载.下拉后分批显示图片.图片高度未知,当图片onload后才显示容器) [思路]: 图片瀑布流,网上代码有多种实现方式,也有各类插件.没找到合意的,所以根据网上找的一段代码,进行了较大改动. 需引用 zepto 或 jquery. 我这个是应用于手机上的,两列瀑布流,图片高度未知——等图片的onloaded事件触发后,才对容器进行计算和定位. 大容器是 $("#imgList"),容器格子是$(".pin"

记录下页面懒加载代码

今天京东在做图书品类的活动,买了几本心仪的书,闲暇之余看了看京东图书促销页前端代码,有很多的工具类js文件,如用于cookie.跨域.数组.业务方面等.突然看到了页面懒加载代码,做下记录. /** * 图片懒加载 */ (function(){ if(jQuery.fn.lazyLoad) return; jQuery.fn.lazyLoad = function(config){ //相关参数 var conf = jQuery.extend({ defClass:"J_imgLazyload

The way of Webpack learning (III.) -- codeSplitting &amp; lazyLoding(代码分割和路由懒加载)

代码分割:对于一个大型的web项目来说,如果为了减少http请求,只打包出一个bundle.js文件,那么只要我们的需求修改了一点点,整个bundle.js都需要重新加载,得不偿失.所以我们不妨把代码分割成一块一块的,按需加载,而且还能利用浏览器缓存机制,如果文件没有修改,直接从缓存读取.也就是说,代码分割就是把代码切成很多块(chunk). 懒加载:按需加载,页面需要什么文件我才去加载什么文件.我现在只知道应用在路由懒加载中,就是根据路由,按需加载不同的文件. 在上一章节提到使用Commonc

js图片缓冲加载代码实例

js图片缓冲加载代码实例:一般的图片展或者图片较多的网站都会使用图片缓冲加载技术,可以说对提高网站的体验度有良好的效果,下面就分享一段网络上的相关代码,希望能够给大家带来一定的帮助,代码如下: <script type="text/javascript"> var Imgvalue; var Count =13;//图片数量 var Imgs = new Array(Count); var ImgLoaded =0; //预加载图片 function preLoadImgs

原生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

JVM虚拟机系列(一)类的加载

JAVA虚拟机系列(一) 类的加载 目录 1 类的初始化过程 2 详解初始化时的各个阶段 一.类初始化的过程 先来看一个CLASS文件在整体生命周期里会遇到的阶段: xxxx.class --->加载---->连接--->初始化---> 使用--->卸载. 我们将会在本章讨论一下xxxx.class--->加载--->连接---->初始化的过程. 讨论的方式采用自问自答模式: 1 首先类什么时候会被加载? 答:这一点JVM并没有强制约束,由不同的JVM供应商