懒加载的效果

<!DOCTYPE html>
<html>
<head>
  <title>懒加载</title>
  <meta charset="utf-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <style>
    body{ background: #eee; }
    ul,li{padding: 0; margin: 0; list-style: none;}
    #main .list-wrap{
      overflow: hidden;
    }
    #main .list-item{
      padding: 5px 0;
      background: #fff;
      border: 1px solid #ccc;
      overflow: hidden;
    }
    #main .pic-wrap{
      float: left;
      margin: 0 10px;
      height: 100px;
      min-width: 50px;
    }
    #main .cont-wrap{
      padding: 5px;
      color: #777;
      font-size: 14px;
      line-height: 1.4;
    }      
  </style>
</head>
<body>
 <div id="main">
  <ul class="list-wrap">
    <li class="list-item amfe-appear">
      <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> 
</li>
<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

<li class="list-item amfe-appear"> <img class="pic-wrap" data-src="你的图片地址" /> <div class="cont-wrap"> 这个效果有点好 </div> </li>

</ul> </div>
<script src="bundle.js"></script>
<script> (function () {

var AmfeAppear = require('amfe-appear'); //宝贝列表实例化,查找类名包含amfe-appear的元素

var itemAppear = AmfeAppear.appear.init({ cls: 'amfe-appear', onAppear: function(){

//元素处在可视区域内,执行懒加载

var img = this.querySelector('img'); // 延迟执行,方便查看效果
setTimeout(
function() {
img.src
= img.getAttribute('data-src'); }, 500); }, onDisappear: function() {

//元素处在不可视区域内,做输出
console.log(
this); } });

// 触发校验 itemAppear.fire(); }) () ;
</script>
</body>
</html>
bundle.js
  1 <script>
  2   /*bundle.js*/
  3   require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  4     'use strict';
  5 
  6     Object.defineProperty(exports, "__esModule", {
  7       value: true
  8     });
  9 
 10     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; }; }();
 11 
 12     function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 13 
 14     var doc = document;
 15     var appearEvt = doc.createEvent("HTMLEvents"); //创建自定义显示事件  ;
 16     var disappearEvt = doc.createEvent("HTMLEvents"); //创建自定义显示事件  ;
 17 
 18     function createEvent(eventType) {
 19       appearEvt.initEvent(eventType, false, true);
 20       disappearEvt.initEvent(eventType, false, true);
 21     }
 22 
 23     /**
 24      * [throttle 节流函数]
 25      * @param  {[function]} func [执行函数]
 26      * @param  {[int]} wait [等待时长]
 27      * @return {[type]}      [description]
 28      */
 29     function throttle(func, wait) {
 30       var previous = 0,
 31       //上次执行的时间
 32               timeout = null,
 33       //setTimout任务
 34               args = void 0,
 35       //参数
 36               result = void 0; //结果
 37       var later = function later() {
 38         previous = Date.now();
 39         timeout = null; //清空计时器
 40         func(args);
 41       };
 42       return function () {
 43         var now = Date.now(),
 44                 args = arguments,
 45                 remaining = wait - (now - previous);
 46         if (remaining <= 0 || remaining >= wait) {
 47           //如果没有剩余时间,或者存在修改过系统时间导致剩余时间增大的情况,则执行
 48           clearTimeout(timeout);
 49           timeout = null;
 50           result = func(args);
 51         } else if (timeout === null) {
 52           timeout = setTimeout(later, remaining);
 53         }
 54         return result;
 55       };
 56     }
 57 
 58     /**
 59      * [getOffset 获取边距尺寸]
 60      * @param  {[type]} el   [description]
 61      * @param  {[type]} param [description]
 62      * @return {[type]}       [description]
 63      */
 64     function getOffset(el, param) {
 65       var l, r, t, b;
 66       if (!el) {
 67         return;
 68       }
 69       if (!param) {
 70         param = {
 71           x: 0,
 72           y: 0,
 73           h: null,
 74           w: null
 75         };
 76       }
 77 
 78       if (el !== window) {
 79         el = el.getBoundingClientRect();
 80         l = el.left;
 81         t = el.top;
 82         r = el.right;
 83         b = el.bottom;
 84       } else {
 85         l = 0;
 86         t = 0;
 87         r = l + el.innerWidth;
 88         b = t + el.innerHeight;
 89       }
 90       param.h = param.h || (el.height || el.innerHeight) - param.y;
 91       param.w = param.w || (el.width || el.innerWidth) - param.x;
 92       var offset = {
 93         'left': l + (el.width || el.innerWidth) - param.w - param.x,
 94         'top': t + (el.height || el.innerHeight) - param.h - param.y,
 95         'right': r - param.x,
 96         'bottom': b - param.y
 97       };
 98       return offset;
 99     }
100 
101 //元素位置比较
102     function compareOffset(d1, d2) {
103       var left = d2.right > d1.left && d2.left < d1.right;
104       var top = d2.bottom > d1.top && d2.top < d1.bottom;
105       return left && top;
106     }
107 //获取移动方向
108     function getDirection(beforeOffset, nowOffset) {
109       var direction = 'none';
110       var horizental = beforeOffset.left - nowOffset.left;
111       var vertical = beforeOffset.top - nowOffset.top;
112       if (vertical === 0) {
113         if (horizental !== 0) {
114           direction = horizental > 0 ? 'left' : 'right';
115         } else {
116           direction = 'none';
117         }
118       }
119       if (horizental === 0) {
120         if (vertical !== 0) {
121           direction = vertical > 0 ? 'up' : 'down';
122         } else {
123           direction = 'none';
124         }
125       }
126       return direction;
127     }
128 
129     function extend(target, el) {
130       for (var k in el) {
131         if (el.hasOwnProperty(k)) {
132           target[k] = el[k];
133         }
134       }
135       return target;
136     }
137 
138     /**
139      * [__bindEvent 绑定事件,包括滚动、touchmove、transform、resize等]
140      * @return {[type]}      [description]
141      */
142     function __bindEvent() {
143       var _this = this,
144               _arguments = arguments;
145 
146       var handle = throttle(function () {
147         __fire.apply(_this, _arguments);
148       }, this.options.wait);
149       if (this.__handle) {
150         //避免重复绑定
151         this.viewWrapper.removeEventListener('scroll', this.__handle);
152         this.__handle = null;
153       }
154       this.__handle = handle;
155       this.viewWrapper.addEventListener('scroll', handle, false);
156       this.viewWrapper.addEventListener('resize', function () {
157         __fire.apply(_this, _arguments);
158       }, false);
159       this.viewWrapper.addEventListener('animationEnd', function () {
160         __fire.apply(_this, _arguments);
161       }, false);
162       // android4.0以下
163       this.viewWrapper.addEventListener('webkitAnimationEnd', function () {
164         __fire.apply(_this, _arguments);
165       }, false);
166       this.viewWrapper.addEventListener('transitionend', function () {
167         __fire.apply(_this, _arguments);
168       }, false);
169     }
170 
171 //获取容器内所有的加载元素
172     function __getElements(selector) {
173       var _this2 = this;
174 
175       //获取视窗容器
176       var viewWrapper = this.options.viewWrapper;
177       if (typeof viewWrapper === 'string') {
178         //如果是字符串,则选择器
179         this.viewWrapper = doc.querySelector(viewWrapper);
180       } else {
181         //对象传值
182         this.viewWrapper = viewWrapper;
183       }
184       var appearWatchElements = void 0;
185       //获取容器内的所有目标元素
186       if (this.viewWrapper === window) {
187         appearWatchElements = doc.querySelectorAll(selector);
188       } else {
189         appearWatchElements = this.viewWrapper.querySelectorAll(selector);
190       }
191       appearWatchElements = [].slice.call(appearWatchElements, null);
192 
193       appearWatchElements = appearWatchElements.filter(function (ele) {
194         // 如果已经绑定过,清除appear状态,不再加入到数组里
195         if (ele.dataset.bind === '1') {
196           delete ele._hasAppear;
197           delete ele._hasDisAppear;
198           delete ele._appear;
199           ele.classList.remove(_this2.options.cls);
200           return false;
201         } else {
202           return true;
203         }
204       });
205 
206       return appearWatchElements;
207     }
208 
209     function __initBoundingRect(elements) {
210       var _this3 = this;
211 
212       if (elements && elements.length > 0) {
213         [].forEach.call(elements, function (ele) {
214           ele._eleOffset = getOffset(ele);
215           //移除类名
216           ele.classList.remove(_this3.options.cls);
217           // 标志已经绑定
218           ele.dataset.bind = 1;
219         });
220       }
221     }
222 
223 // 触发加载
224     function __fire() {
225       var viewWrapper = this.viewWrapper,
226               elements = this.appearWatchElements,
227               appearCallback = this.options.onAppear,
228       //appear的执行函数
229               isDispatch = this.options.isDispatch,
230       // 是否分发事件
231               disappearCallback = this.options.onDisappear,
232       //disappear的执行函数
233               viewWrapperOffset = getOffset(viewWrapper, {
234                 x: this.options.x,
235                 y: this.options.y,
236                 h: this.options.h,
237                 w: this.options.w
238               }),
239               isOnce = this.options.once; //是否只执行一次
240       if (elements && elements.length > 0) {
241         [].forEach.call(elements, function (ele) {
242           //获取左右距离
243           var eleOffset = getOffset(ele),
244                   direction = getDirection(ele._eleOffset, eleOffset);
245           //保存上个时段的位置信息
246           ele._eleOffset = eleOffset;
247           //查看是否在可视区域范围内
248           var isInView = compareOffset(viewWrapperOffset, eleOffset),
249                   appear = ele._appear,
250                   _hasAppear = ele._hasAppear,
251                   _hasDisAppear = ele._hasDisAppear;
252           appearEvt.data = {
253             direction: direction,
254             eleOffset: eleOffset
255           };
256           disappearEvt.data = {
257             direction: direction,
258             eleOffset: eleOffset
259           };
260           if (isInView && !appear) {
261             if (isOnce && !_hasAppear || !isOnce) {
262               //如果只触发一次并且没有触发过或者允许触发多次
263               //如果在可视区域内,并且是从disppear进入appear,则执行回调
264               var appearFn = function appearFn(ev) {
265                 appearCallback && appearCallback.call(ele, ev);
266                 ele.removeEventListener('appear', appearFn);
267               };
268               ele.addEventListener('appear', appearFn);
269               if (isDispatch) {
270                 //触发自定义事件
271                 ele.dispatchEvent(appearEvt);
272               } else {
273                 appearFn(appearEvt);
274               }
275               ele._hasAppear = true;
276               ele._appear = true;
277             }
278           } else if (!isInView && appear) {
279             if (isOnce && !_hasDisAppear || !isOnce) {
280               //如果不在可视区域内,并且是从appear进入disappear,执行disappear回调
281               var disappearFn = function disappearFn(ev) {
282                 disappearCallback && disappearCallback.call(ele, ev);
283                 ele.removeEventListener('disappear', disappearFn);
284               };
285               ele.addEventListener('disappear', disappearFn);
286 
287               if (isDispatch) {
288                 //触发自定义事件
289                 ele.dispatchEvent(disappearEvt);
290               } else {
291                 disappearFn(disappearEvt);
292               }
293               ele._hasDisAppear = true;
294               ele._appear = false;
295             }
296           }
297         });
298       }
299     }
300 
301     function __init(opts) {
302       //扩展参数
303       extend(this.options, opts || (opts = {}));
304       //注册事件
305       createEvent(this.options.eventType);
306       //获取目标元素
307       this.appearWatchElements = this.appearWatchElements || __getElements.call(this, "." + this.options.cls);
308       //初始化位置信息
309       __initBoundingRect.call(this, this.appearWatchElements);
310       //绑定事件
311       __bindEvent.call(this);
312     }
313 
314     var Appear = function () {
315       function Appear() {
316         _classCallCheck(this, Appear);
317 
318         //默认参数
319         this.options = {
320           viewWrapper: window,
321           wait: 100,
322           x: 0,
323           y: 0,
324           w: null,
325           h: null,
326           cls: 'amfe-appear',
327           once: false,
328           isDispatch: true,
329           eventType: 'appear', // 事件类型,默认出现事件为appear、消失事件为disappear,自定义事件名,消失事件自动加上前缀dis
330           onAppear: function onAppear() {},
331           onDisappear: function onDisappear() {}
332         };
333         this.viewWrapper = null;
334         this.appearWatchElements = null;
335         __init.apply(this, arguments);
336       }
337 
338       _createClass(Appear, [{
339         key: "bind",
340         value: function bind(node) {
341           var cls = this.options.cls;
342           // 添加需要绑定的appear元素
343           if (typeof node === 'string') {
344             var elements = __getElements.call(this, node);
345             [].forEach.call(elements, function (ele) {
346               if (!ele.classList.contains(cls)) {
347                 ele.classList.add(cls);
348               }
349             });
350           } else if (node.nodeType === 1 && (this.viewWrapper === window || this.viewWrapper.contains(node))) {
351             //如果传入的是元素并且在包含在容器中,直接添加类名
352             if (!node.classList.contains(cls)) {
353               //添加类名
354               node.classList.add(cls);
355             }
356           } else {
357             return this;
358           }
359           //新增的子元素
360           var newElements = __getElements.call(this, "." + this.options.cls);
361           //对缓存的子元素做增量
362           this.appearWatchElements = this.appearWatchElements.concat(newElements);
363           //初始化新子元素的位置信息
364           __initBoundingRect.call(this, newElements);
365           return this;
366         }
367         // 重置函数
368 
369       }, {
370         key: "reset",
371         value: function reset(opts) {
372           __init.call(this, opts);
373           this.appearWatchElements.forEach(function (ele) {
374             delete ele._hasAppear;
375             delete ele._hasDisAppear;
376             delete ele._appear;
377           });
378           return this;
379         }
380       }, {
381         key: "fire",
382         value: function fire() {
383           if (!this.appearWatchElements) {
384             this.appearWatchElements = [];
385           }
386           var newElements = __getElements.call(this, "." + this.options.cls);
387           this.appearWatchElements = this.appearWatchElements.concat(newElements);
388           //初始化位置信息
389           __initBoundingRect.call(this, newElements);
390           __fire.call(this);
391           return this;
392         }
393       }]);
394 
395       return Appear;
396     }();
397 
398     var appear = {
399       instances: [],
400       init: function init(opts) {
401         var instance = new Appear(opts);
402         this.instances.push(instance);
403         return instance;
404       },
405       fireAll: function fireAll() {
406         var instances = this.instances;
407         instances.forEach(function (instance) {
408           instance.fire();
409         });
410       }
411     };
412 
413     exports.default = appear;
414 
415   },{}],"amfe-appear":[function(require,module,exports){
416     'use strict';
417 
418     /**
419      * @module amfeAppear
420      */
421 
422     /**
423      * @requires class:Appear
424      */
425 
426     Object.defineProperty(exports, "__esModule", {
427       value: true
428     });
429     exports.appear = exports.version = undefined;
430 
431     var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
432 
433     var _appear = require('./appear');
434 
435     var _appear2 = _interopRequireDefault(_appear);
436 
437     function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
438 
439     var version = '1.0.0';
440     /*eslint-disable no-alert, no-console */
441 
442     /* istanbul ignore if */
443     if (typeof alert === 'function' && (typeof console === 'undefined' ? 'undefined' : _typeof(console)) === 'object') {
444       console.log('bar');
445     }
446 
447     /*eslint-enable no-alert, no-console */
448 
449     exports.
450     /**
451      * version
452      * @type {string}
453      */
454             version = version;
455     exports.
456     /**
457      * @type {Appear}
458      */
459             appear = _appear2.default;
460 
461   },{"./appear":1}]},{},[])
462 </script>
js源码

效果图就不上了,就是懒加载的效果

原文地址:https://www.cnblogs.com/heyiming/p/6873979.html