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

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

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

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

    参考学习:https://alexjover.com/blog/lazy-load-in-vue-using-webpack-s-code-splitting/ 学习文案:https://webpac ...

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

    教程所示图片使用的是 github 仓库图片,网速过慢的朋友请移步>>> (原文)webpack4 系列教程(七): SCSS 提取和懒加载. 个人技术小站: https://god ...

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

    本节课讲解webpack4打包单页应用过程中的代码分割和代码懒加载.不同于多页面应用的提取公共代码,单页面的代码分割和懒加载不是通过webpack配置来实现的,而是通过webpack的写法和内置函数实 ...

  4. 【Java EE 学习 47】【Hibernate学习第四天】【sesion】【一级缓存】【懒加载】

    一.Session概述 1.Session 接口是 Hibernate 向应用程序提供的操纵对数据库的最主要的接口, 它提供了基本的保存, 更新, 删除和加载Java 对象的方法. 2.理解Sessi ...

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

    代码: 两列图片瀑布流(一次后台取数据,无ajax,图片懒加载.下拉后分批显示图片.图片高度未知,当图片onload后才显示容器) [思路]: 图片瀑布流,网上代码有多种实现方式,也有各类插件.没找到 ...

  6. 【SpringBoot 基础系列】实现一个自定义配置加载器(应用篇)

    [SpringBoot 基础系列]实现一个自定义配置加载器(应用篇) Spring 中提供了@Value注解,用来绑定配置,可以实现从配置文件中,读取对应的配置并赋值给成员变量:某些时候,我们的配置可 ...

  7. Spring5.0源码学习系列之浅谈懒加载机制原理

    前言介绍 附录:Spring源码学习专栏 在上一章的学习中,我们对Bean的创建有了一个粗略的了解,接着本文挑一个比较重要的知识点Bean的懒加载进行学习 1.什么是懒加载? 懒加载(Lazy-ini ...

  8. Vue总结第五天:vue-router (使用模块化(创建Vue组件)机制编程)、router-link 标签的属性、路由代码跳转、懒加载、路由嵌套(子路由)、路由传递数据、导航守卫)

    Vue总结第五天:vue-router ✿ 路由(器)目录: □  vue中路由作用 □  vue-router基本使用 □  vue-router嵌套路由 □  vue-router参数传递 □  ...

  9. [IOS 开发] 懒加载 (延迟加载) 的基本方式,好处,代码示例

    懒加载的好处: 1> 不必将创建对象的代码全部写在viewDidLoad方法中,代码的可读性更强 2> 每个属性的getter方法中分别负责各自的实例化处理,代码彼此之间的独立性强,松耦合 ...

随机推荐

  1. servlet api.jar是干什么的?

    支持servlet的jar包.应该叫servlet-api.jar你如果编写过servlet就知道要用到HttpServletRequest和HttpServletResponse等对象,这些对象都是 ...

  2. 字符串拼接+和concat的区别

    +和concat都可以用来拼接字符串,但在使用上有什么区别呢,先来看看这个例子. public static void main(String[] args) { // example1 String ...

  3. 阅读HandlerInterceptor接口源码的理解

    一.阅读接口类注释 我先理解的方法,方法都看懂了类注释自然而然明白了.所以此处略. 二.阅读preHandle()方法注释 Intercept the execution of a handler. ...

  4. Volecity模板引擎学习笔记

    转自:https://blog.csdn.net/reggergdsg/article/details/50937433 最近项目中用到了volecity模板,这里做一下笔记,学习中...相比较 Fr ...

  5. Mysql数据库的简单语法

    Mysql数据库是目前使用最为广泛的数据对,对于小型企业的支持度,比oracle数据库友好很多. mysql数据库的基本语法 1:创建并且使用数据库 找出服务器上当前存在什么数据库: SHOW DAT ...

  6. VB.NET的一个邮件发送函数

    ''' <summary> ''' VB.NET邮件发送程序 ''' 还没用在别的服务器,不晓得能不能行,慎用! ''' </summary> ''' <param na ...

  7. Gradle Goodness: Check Task Dependencies With a Dry Run

    We can run a Gradle build without any of the task actions being executed. This is a so-called dry ru ...

  8. 关于session序列化和session钝化和活化

    在第一次启动服务器后,在session中放入一个对象.在页面可以获得,当重启服务器,但是没有关闭浏览器的情况下刷新页面仍然能够获得这个对象,前提是这个对象必须实现了java.io.Serializab ...

  9. java连接linux的三种方式(附执行命令)

    # 本地调用使用JDK自带的RunTime类和Process类实现 public static void main(String[] args){ Process proc = RunTime.get ...

  10. 关于ORA-00257: archiver error. Connect internal only, until freed 错误的处理方法

    转 关于ORA-00257: archiver error. Connect internal only, until freed 错误的处理方法 2016年03月31日 10:14:59 阅读数:1 ...