前文有简单的实现了一个制作懒加载的方法,但其实以方法的形式做插件扩展性不强。那么本文就来用面向对象的方法将其制作成一个真正的插件:
我想要的最终的调用效果是:
1 $(".loading").lazyLoadDiv_cc({ 2 //自定义效果,可不填 3 "beginHeight":400, 4 "loadingBgClass":"loading", 5 "whenToLoad":"someIn" 6 });
分析一下,需要扩展jquery的实例如:$(".loading")的方法。插件肯定要用到$这个方法。所以初步原型是:
1 ;(function($){ 2 $.fn.lazyLoad=function(this,options){ 3 //处理代码 4 }; 5 })(jQuery);
你可能会问的问题:
- 为什么前面加封号? 答:防止该插件之前的代码忘记加封号。影响代码解析;
- 为什么使用匿名函数?答:写js的一个原则是尽量不要污染全局变量。插件如果足够庞大,肯定把所有属性和方法都暴露给全局。由于js中没有语句的块级作用域,所以这里使用立即执行的匿名函数。将不需要暴露给全局,但是插件的逻辑要用到得部分代码放到函数的局部作用域中。这样就不会和其他的插件命名冲突啦。
- 为什么参数要传jQuery?答:这里其实不传也不会报错,但是为了保证代码的独立性,传一下其实更保险。类似window,document这种都可以传进来。
tips:这里见缝插针,说下jquery和jquery的原型。
1.$是什么?
从jquery源码开始分析:
第一次出现jQuery:
由图得知,jquery是一个函数。函数的入参是selector和context,返回一个实例。
So,$("#div2")是一个实例,拥有很多方法,方法大部分在jQuery原型里面。
暴露给全局变量:
可知$和jQuery其实是同一个函数。
2.$.fn是什么?
源码中:
jQuery.fn = jQuery.prototype=$.fn
所以它是jQuery和$对象的原型。在它里面添加方法相当于$的实例(如$("#div1"))都能调用到。
---------------------------------------------我是一个分割线-------------------------------------------
言归正传,初步的模型并没有用到面向对象的特性。当插件越来越庞大时,面向过程就会变得逻辑混乱,难于管理,难于扩展。so。咱们再改一下
1 ;(function($){ 2 var lazyloadPlugin=function(ele,opt){ 3 this.elements=ele?ele:$(".loading"),//若没有第一个参数,默认获取class为loading的元素 4 this.defaults={ 5 //参数的默认值 6 "beginHeight":0, 7 "howToLoad":"fadeIn", 8 "loadingBgClass":"loading",//定义未加载前背景图片的类名 9 "whenToLoad":"allIn"//默认为div全部在可视窗口内开始加载;其他值:“someIn” 10 }, 11 this.options=$.extend({},this.defaults,opt) 12 }; 13 lazyloadPlugin.prototype={ 14 bindLazy:function(){ 15 //实现代码 16 } 17 }; 18 //以上相当于MVC中的模型层,不需要关心逻辑怎么串起来 19 $.fn.lazyLoadDiv_cc=function(options){ 20 //相当于MVC中的业务逻辑层,需要组织逻辑 21 var llp=new lazyloadPlugin(this,options); 22 return llp.bindLazy(); 23 }; 24 })(jQuery);
lazyloadPlugin是定义在匿名函数中的对象,除了调用lazyLoadDiv_cc方法,并没有其他方式可以使用它。因此它的各种属性和方法都很安全。特别是它的原型,因为实例没有办法改变原型,所以原型中的方法是不可修改的,很安全。
通过这一层封装,我们只暴露出来了一个看似简单的方法。却实现了可扩展、独立性强、保证性能的方法。
1.可扩展性。
通过options入参,可以实现不同用户的需求。例如options中的whenToLoad字段,可以通过定义不同的值,让插件在不同的位置触发懒加载。
同时,options在构造函数中定义了默认值。更健壮。
2.独立性强
将大部分属性封装起来,通过匿名函数+闭包,让代码更简洁安全
3.保证性能
根据共享的放在原型中,不共享的放在构造函数中这一原则。将默认值都放在对象的构造函数中,而方法的实现放在原型中。方法部分的内存共享,提高性能。
只是一个简单的例子,就用到了原型、闭包、this、匿名函数等多个知识点,多多实践比只看书真的好多啦。
实现逻辑之后,网上有在线压缩工具。所谓压缩,只是把变量语义化的名字名字改为更短的,多行也改为了一行,文件体积确实是压缩了,但是逻辑一点也没少哦。
本次插件地址:
压缩后-https://github.com/HappyBangs/bang_plugins/blob/master/plugin_TmallLazyLoad/version2.0/lazyload_pcc.min.js
压缩前-https://github.com/HappyBangs/bang_plugins/blob/master/plugin_TmallLazyLoad/version2.0/lazyload_pcc.js