原生js开发,无依赖、轻量级的现代浏览器图片懒加载插件,适合在移动端开发使用
优势
1.原生js开发,不依赖任何框架或库
2.支持将各种宽高不一致的图片,自动剪切成默认图片的宽高
比如说你的默认图片是一张正方形的图片,则各种宽度高度不一样的图片,自动剪切成正方形。
完美解决移动端开发中,用户上传图片宽高不一致而导致的图片变形的问题
3.简洁的API,让你分分钟入门!!!
代码如下【默认模式,不对图片进行剪切】:<!DOCTYPE html><html lang="en">
<head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui"> <title>默认模式,不对图片进行剪切</title> <style> * { padding: 0; margin: 0; list-style: none; } img { border: none; width: 100%; } .success { -webkit-animation: fadeIn 01s ease 0.2s 1 both; animation: fadeIn 1s ease 0.2s 1 both; } @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } </style> </head> <body> <ul id="list"> <li><img src="./images/default.png" data-src="./images/1.jpg"></li> <li><img src="./images/default.png" data-src="./images/2.jpg"></li> <li><img src="./images/default.png" data-src="./images/3.jpg"></li> <li><img src="./images/default.png" data-src="./images/4.jpg"></li> <li><img src="./images/default.png" data-src="./images/5.jpg"></li> <li><img src="./images/default.png" data-src="./images/6.jpg"></li> <li><img src="./images/default.png" data-src="./images/7.jpg"></li> <li><img src="./images/default.png" data-src="./images/8.jpg"></li> <li><img src="./images/default.png" data-src="./images/9.jpg"></li> <li><img src="./images/default.png" data-src="./images/10.jpg"></li> <li><img src="./images/default.png" data-src="./images/11.jpg"></li> <li><img src="./images/default.png" data-src="./images/12.jpg"></li> <li><img src="./images/default.png" data-src="./images/13.jpg"></li> <li><img src="./images/default.png" data-src="./images/14.jpg"></li> <li><img src="./images/default.png" data-src="./images/15.jpg"></li> <li><img src="./images/default.png" data-src="./images/16.jpg"></li> <li><img src="./images/default.png" data-src="./images/17.jpg"></li> <li><img src="./images/default.png" data-src="./images/18.jpg"></li> <li><img src="./images/default.png" data-src="./images/19.jpg"></li> <li><img src="./images/default.png" data-src="./images/20.jpg"></li> <li><img src="./images/default.png" data-src="./images/21.jpg"></li> </ul> <script> /** * Created by Sorrow.X on 2017/4/27. */ ;(function(exports) { class LazyLoadImg { constructor() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.options = { // 实例的option属性(默认) el: document.querySelector('body'), // 选择的元素 mode: 'default', // 默认模式,将显示原图,diy模式,将自定义剪切,默认剪切居中部分 time: 300, // 设置一个检测时间间隔 done: true, // 页面内所有数据图片加载完成后,是否自己销毁程序,true默认销毁,false不销毁:FALSE应用场景:页面异步不断获取数据的情况下 需要实时监听则不销毁 diy: { // 此属性,只有在设置diy 模式时才生效 backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: 'center center' }, position: { // 只要其中一个位置符合条件,都会触发加载机制 top: 0, // 元素距离顶部 right: 0, // 元素距离右边 bottom: 0, // 元素距离下面 left: 0 // 元素距离左边 }, before: function before(el) {// 图片加载之前,执行钩子函数 }, success: function success(el) {// 图片加载成功,执行钩子函数 }, error: function error(el) {// 图片加载失败,执行的钩子函数 } }; Object.assign({}, this.options, options); Object.assign({}, this.options.diy, options.diy); Object.assign(this.options, options); // 裁切图片用的 this.canvas = document.createElement('canvas'); this.canvas.getContext('2d').globalAlpha = 0.0; this.images = {}; this._timer = true; // 给实例添加一个_timer属性(定时器) this.start(); // 开启懒加载程序 } _testMeet(el) { // 每个dom元素,一般img元素 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // position对象 // 取得元素在可视区的位置(相对浏览器视窗)左右上下 var bcr = el.getBoundingClientRect(); // padding+border+width var mw = el.offsetWidth; // 元素自身宽度 var mh = el.offsetHeight; // 元素自身的高度 // 包含了导航栏 var w = window.innerWidth; // 视窗的宽度 var h = window.innerHeight; // 视窗的高度 var boolX = !(bcr.right - options.left <= 0 && bcr.left + mw - options.left <= 0) && !(bcr.left + options.right >= w && bcr.right + options.right >= mw + w); // 左右符合条件 var boolY = !(bcr.bottom - options.top <= 0 && bcr.top + mh - options.top <= 0) && !(bcr.top + options.bottom >= h && bcr.bottom + options.bottom >= mh + h); // 上下符合条件 return el.width !== 0 && el.height !== 0 && boolX && boolY; } _getTransparent(src, w, h) { if (this.images[src]) return this.images[src]; this.canvas.width = w; this.canvas.height = h; var data = this.canvas.toDataURL('image/png'); this.images[src] = data; return data; } start() { var self = this; // LazyLoadImg实例存一下 var options = this.options; // 配置存一下 clearTimeout(this._timer); // 清除定时器 if (!this._timer) return; // this._timer 是setTimeout的return flag 推荐采用settimeout的方法,而不是setinterval this._timer = setTimeout(function () { var list = Array.prototype.slice.apply(options.el.querySelectorAll('[data-src]')); // 获取el下所有含有data-src属性的标签,且转成数组 // 如果list.length为0 且页面内图片已经加载完毕 清空setTimeout循环 if (!list.length && options.done) { // list有数据就不关闭定时器 clearTimeout(self._timer); // 有页面内的图片加载完成了,自己销毁程序
return false;
} else { list.forEach(function (el) { // 遍历dom // 如果该元素状态为空(dataset HTML5方法 设置、获取属性);并且检测该元素的位置 if (!el.dataset.LazyLoadImgState && self._testMeet(el, options.position)) { self.loadImg(el); // 加载图片 }; }); }; // call it self.start(); }, options.time); } loadImg(el) { var self = this; // 加载图片 var options = this.options; el.dataset.LazyLoadImgState = 'start'; // 执行加载之前做的事情 options.before.call(this, el); var img = new window.Image(); // 这里是一个坑 dataset.src 实际取的值是 属性data-src data- 是HTML5 DOMStringMap对象 img.src = el.dataset.src; // 图片加载成功 img.addEventListener('load', function () { if (options.mode === 'diy') { el.src = self._getTransparent(el.src, el.width, el.height); options.diy.backgroundImage = 'url(' + img.src + ')'; Object.assign(el.style, options.diy); } else { el.src = img.src; }; delete el.dataset.src; el.dataset.LazyLoadImgState = 'success'; return options.success.call(self, el); }, false); // 图片加载失败 img.addEventListener('error', function () { delete el.dataset.src; el.dataset.LazyLoadImgState = 'error'; options.error.call(self, el); }, false); } destroy() { // 解除事件绑定,return掉,不会自调用 delete this._timer; } restart() { this._timer = true; this.start(); } }; exports.LazyLoadImg = LazyLoadImg; })(window); </script> <script> ; (function () { var lazyLoadImg = new LazyLoadImg({ el: document.querySelector('#list'), mode: 'default', //默认模式,将显示原图,diy模式,将自定义剪切,默认剪切居中部分 time: 300, // 设置一个检测时间间隔 complete: true, //页面内所有数据图片加载完成后,是否自己销毁程序,true默认销毁,false不销毁 position: { // 只要其中一个位置符合条件,都会触发加载机制 top: 0, // 元素距离顶部 right: 0, // 元素距离右边 bottom: 0, // 元素距离下面,传递负数即为预加载 left: 0 // 元素距离左边 }, before: function () { // 图片加载之前执行方法 }, success: function (el) { // 图片加载成功执行方法 el.classList.add('success') }, error: function (el) { // 图片加载失败执行方法 el.src = './images/error.png' } }) // lazyLoadImg.start() // 重新开启懒加载程序 // lazyLoadImg.destroy() // 销毁图片懒加载程序 })() </script> </body> </html>
代码如下【自定义模式,设置对图片的剪切规则】:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width,initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no,minimal-ui"> <title>自定义模式,设置对图片的剪切规则</title> <style> * { padding: 0; margin: 0; list-style: none; } img { border: none; width: 100%; } .success { -webkit-animation: fadeIn 01s ease 0.2s 1 both; animation: fadeIn 1s ease 0.2s 1 both; } @-webkit-keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } </style> </head> <body> <ul id="list"> <li><img src="./images/default.png" data-src="./images/1.jpg"></li> <li><img src="./images/default.png" data-src="./images/2.jpg"></li> <li><img src="./images/default.png" data-src="./images/3.jpg"></li> <li><img src="./images/default.png" data-src="./images/4.jpg"></li> <li><img src="./images/default.png" data-src="./images/5.jpg"></li> <li><img src="./images/default.png" data-src="./images/6.jpg"></li> <li><img src="./images/default.png" data-src="./images/7.jpg"></li> <li><img src="./images/default.png" data-src="./images/8.jpg"></li> <li><img src="./images/default.png" data-src="./images/9.jpg"></li> <li><img src="./images/default.png" data-src="./images/10.jpg"></li> <li><img src="./images/default.png" data-src="./images/11.jpg"></li> <li><img src="./images/default.png" data-src="./images/12.jpg"></li> <li><img src="./images/default.png" data-src="./images/13.jpg"></li> <li><img src="./images/default.png" data-src="./images/14.jpg"></li> <li><img src="./images/default.png" data-src="./images/15.jpg"></li> <li><img src="./images/default.png" data-src="./images/16.jpg"></li> <li><img src="./images/default.png" data-src="./images/17.jpg"></li> <li><img src="./images/default.png" data-src="./images/18.jpg"></li> <li><img src="./images/default.png" data-src="./images/19.jpg"></li> <li><img src="./images/default.png" data-src="./images/20.jpg"></li> <li><img src="./images/default.png" data-src="./images/21.jpg"></li> </ul> <script> /** * Created by Sorrow.X on 2017/4/27. */ ;(function(exports) { class LazyLoadImg { constructor() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; this.options = { // 实例的option属性(默认) el: document.querySelector('body'), // 选择的元素 mode: 'default', // 默认模式,将显示原图,diy模式,将自定义剪切,默认剪切居中部分 time: 300, // 设置一个检测时间间隔 done: true, // 页面内所有数据图片加载完成后,是否自己销毁程序,true默认销毁,false不销毁:FALSE应用场景:页面异步不断获取数据的情况下 需要实时监听则不销毁 diy: { // 此属性,只有在设置diy 模式时才生效 backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: 'center center' }, position: { // 只要其中一个位置符合条件,都会触发加载机制 top: 0, // 元素距离顶部 right: 0, // 元素距离右边 bottom: 0, // 元素距离下面 left: 0 // 元素距离左边 }, before: function before(el) {// 图片加载之前,执行钩子函数 }, success: function success(el) {// 图片加载成功,执行钩子函数 }, error: function error(el) {// 图片加载失败,执行的钩子函数 } }; Object.assign({}, this.options, options); Object.assign({}, this.options.diy, options.diy); Object.assign(this.options, options); // 裁切图片用的 this.canvas = document.createElement('canvas'); this.canvas.getContext('2d').globalAlpha = 0.0; this.images = {}; this._timer = true; // 给实例添加一个_timer属性(定时器) this.start(); // 开启懒加载程序 } _testMeet(el) { // 每个dom元素,一般img元素 var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // position对象 // 取得元素在可视区的位置(相对浏览器视窗)左右上下 var bcr = el.getBoundingClientRect(); // padding+border+width var mw = el.offsetWidth; // 元素自身宽度 var mh = el.offsetHeight; // 元素自身的高度 // 包含了导航栏 var w = window.innerWidth; // 视窗的宽度 var h = window.innerHeight; // 视窗的高度 var boolX = !(bcr.right - options.left <= 0 && bcr.left + mw - options.left <= 0) && !(bcr.left + options.right >= w && bcr.right + options.right >= mw + w); // 左右符合条件 var boolY = !(bcr.bottom - options.top <= 0 && bcr.top + mh - options.top <= 0) && !(bcr.top + options.bottom >= h && bcr.bottom + options.bottom >= mh + h); // 上下符合条件 return el.width !== 0 && el.height !== 0 && boolX && boolY; } _getTransparent(src, w, h) { if (this.images[src]) return this.images[src]; this.canvas.width = w; this.canvas.height = h; var data = this.canvas.toDataURL('image/png'); this.images[src] = data; return data; } start() { var self = this; // LazyLoadImg实例存一下 var options = this.options; // 配置存一下 clearTimeout(this._timer); // 清除定时器 if (!this._timer) return; // this._timer 是setTimeout的return flag 推荐采用settimeout的方法,而不是setinterval this._timer = setTimeout(function () { var list = Array.prototype.slice.apply(options.el.querySelectorAll('[data-src]')); // 获取el下所有含有data-src属性的标签,且转成数组 // 如果list.length为0 且页面内图片已经加载完毕 清空setTimeout循环 if (!list.length && options.done) { // list有数据就不关闭定时器 clearTimeout(self._timer); // 有页面内的图片加载完成了,自己销毁程序
return false;
} else { list.forEach(function (el) { // 遍历dom // 如果该元素状态为空(dataset HTML5方法 设置、获取属性);并且检测该元素的位置 if (!el.dataset.LazyLoadImgState && self._testMeet(el, options.position)) { self.loadImg(el); // 加载图片 }; }); }; // call it self.start(); }, options.time); } loadImg(el) { var self = this; // 加载图片 var options = this.options; el.dataset.LazyLoadImgState = 'start'; // 执行加载之前做的事情 options.before.call(this, el); var img = new window.Image(); // 这里是一个坑 dataset.src 实际取的值是 属性data-src data- 是HTML5 DOMStringMap对象 img.src = el.dataset.src; // 图片加载成功 img.addEventListener('load', function () { if (options.mode === 'diy') { el.src = self._getTransparent(el.src, el.width, el.height); options.diy.backgroundImage = 'url(' + img.src + ')'; Object.assign(el.style, options.diy); } else { el.src = img.src; }; delete el.dataset.src; el.dataset.LazyLoadImgState = 'success'; return options.success.call(self, el); }, false); // 图片加载失败 img.addEventListener('error', function () { delete el.dataset.src; el.dataset.LazyLoadImgState = 'error'; options.error.call(self, el); }, false); } destroy() { // 解除事件绑定,return掉,不会自调用 delete this._timer; } restart() { this._timer = true; this.start(); } }; exports.LazyLoadImg = LazyLoadImg; })(window); </script> <script> ; (function () { var lazyLoadImg = new LazyLoadImg({ el: document.querySelector('#list'), mode: 'diy', //默认模式,将显示原图,diy模式,将自定义剪切,默认剪切居中部分 time: 300, // 设置一个检测时间间隔 complete: true, //页面内所有数据图片加载完成后,是否自己销毁程序,true默认销毁,false不销毁 position: { // 只要其中一个位置符合条件,都会触发加载机制 top: 0, // 元素距离顶部 right: 0, // 元素距离右边 bottom: 0, // 元素距离下面,传递负数即为预加载 left: 0 // 元素距离左边 }, diy: { //设置图片剪切规则,diy模式时才有效果 backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: 'center center' }, before: function () { // 图片加载之前执行方法 }, success: function (el) { // 图片加载成功执行方法 el.classList.add('success') }, error: function (el) { // 图片加载失败执行方法 el.src = './images/error.png' } }) // lazyLoadImg.start() // 重新开启懒加载程序 // lazyLoadImg.destroy() // 销毁图片懒加载程序 })() </script> </body> </html>
vue懒加载js
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : typeof define === 'function' && define.amd ? define(factory) : (global.LazyLoadImg = factory()); }(this, (function () { 'use strict'; var testMeet = function (el) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; // 取得元素在可视区的位置(相对浏览器视窗)左右上下 var bcr = el.getBoundingClientRect(); // padding+border+width var mw = el.offsetWidth; // 元素自身宽度 var mh = el.offsetHeight; // 元素自身的高度 // 包含了导航栏 var w = window.innerWidth; // 视窗的宽度 var h = window.innerHeight; // 视窗的高度 var boolX = !(bcr.right - options.left <= 0 && bcr.left + mw - options.left <= 0) && !(bcr.left + options.right >= w && bcr.right + options.right >= mw + w); // 左右符合条件 var boolY = !(bcr.bottom - options.top <= 0 && bcr.top + mh - options.top <= 0) && !(bcr.top + options.bottom >= h && bcr.bottom + options.bottom >= mh + h); // 上下符合条件 return el.width !== 0 && el.height !== 0 && boolX && boolY; }; var classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }; var createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var GetTransparent = function () { function GetTransparent() { classCallCheck(this, GetTransparent); this.images = {}; this.canvas = document.createElement('canvas'); this.canvas.getContext('2d').globalAlpha = 0.0; } createClass(GetTransparent, [{ key: 'toBase64', value: function toBase64(src, w, h) { if (this.images[src]) return this.images[src]; this.canvas.width = w; this.canvas.height = h; var data = this.canvas.toDataURL('image/png'); this.images[src] = data; return data; } }, { key: 'destroy', value: function destroy() { this.images = null; this.canvas = null; } }]); return GetTransparent; }(); var LazyLoadImg = function () { // 构造函数 初始化参数 function LazyLoadImg() { var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; classCallCheck(this, LazyLoadImg); this.options = { el: document.querySelector('body'), // 选择的元素 mode: 'default', // 默认模式,将显示原图,diy模式,将自定义剪切,默认剪切居中部分 time: 300, // 设置一个检测时间间隔 done: true, // 页面内所有数据图片加载完成后,是否自己销毁程序,true默认销毁,false不销毁:FALSE应用场景:页面异步不断获取数据的情况下 需要实时监听则不销毁 diy: { // 此属性,只有在设置diy 模式时才生效 backgroundSize: 'cover', backgroundRepeat: 'no-repeat', backgroundPosition: 'center center' }, position: { // 只要其中一个位置符合条件,都会触发加载机制 top: 0, // 元素距离顶部 right: 0, // 元素距离右边 bottom: 0, // 元素距离下面 left: 0 // 元素距离左边 }, before: function before(el) {// 图片加载之前,执行钩子函数 }, success: function success(el) {// 图片加载成功,执行钩子函数 }, error: function error(el) {// 图片加载失败,执行的钩子函数 } }; // 深拷贝 如果都有 则右面的值 option.position会覆盖this.options.position options.position = _extends({}, this.options.position, options.position); options.diy = _extends({}, this.options.diy, options.diy); _extends(this.options, options); this.start(); } createClass(LazyLoadImg, [{ key: 'start', value: function start() { if (!this._getTransparent) { this._getTransparent = new GetTransparent(); } this._timer = true; this._start(); } }, { key: '_start', value: function _start() { var _this = this; var options = this.options; clearTimeout(this._timer); // 清除定时器 if (!this._timer) return; this._timer = setTimeout(function () { var list = Array.prototype.slice.apply(options.el.querySelectorAll('[data-src]')); if (!list.length && options.done) return clearTimeout(_this._timer); list.forEach(function (el) { if (!el.dataset.LazyLoadImgState && testMeet(el, options.position)) { _this.loadImg(el); } }); _this._start(); }, options.time); } }, { key: 'loadImg', value: function loadImg(el) { var _this2 = this; // 加载图片 var options = this.options; el.dataset.LazyLoadImgState = 'start'; options.before.call(this, el); var img = new window.Image(); img.src = el.dataset.src; // 图片加载成功 img.addEventListener('load', function () { if (options.mode === 'diy') { el.src = _this2._getTransparent.toBase64(el.src, el.width, el.height); options.diy.backgroundImage = 'url(' + img.src + ')'; _extends(el.style, options.diy); } else { el.src = img.src; } delete el.dataset.src; delete el.dataset.LazyLoadImgState; return options.success.call(_this2, el); }, false); // 图片加载失败 img.addEventListener('error', function () { delete el.dataset.src; delete el.dataset.LazyLoadImgState; options.error.call(_this2, el); }, false); } }, { key: 'destroy', value: function destroy() { // 解除事件绑定 delete this._timer; this._getTransparent.destroy(); this._getTransparent = null; } }]); return LazyLoadImg; }(); return LazyLoadImg; }))); //# sourceMappingURL=lazy-load-img.js.map