jQuery插件编写学习+实例——无限滚动
最近自己在搞一个网站,需要用到无限滚动分页,想想工作两年有余了,竟然都没有写过插件,实在惭愧,于是简单学习了下jQuery的插件编写,然后分享出来。
先说下基础知识,基本上分为两种,一种是对象级别的插件,另一种是全局级别的插件。对象级别的插件就像是实例方法,它是属于实例对象的,而全局级别的相当于静态方法,是属于类的,调用起来自然也就不一样,对于全局级别的插件我们自然是使用jQuery来调用,比如$.NPScrollLoad(....),对象级别的插件自然是应用与jQuery对象上了,比如:$("selector").NPScrollLoad(...)。这个不难理解吧。
对于$.NPScrollLoad()这种形式,我们要对jQuery进行扩展,怎么扩展呢,很简单,就像给对象赋值一样
方法1:
方法2:
这就是在博客园,发布博客界面测试的,F12打开开发者工具,切换到Console,先输入运行"$",确认页面引入了jQuery,然后扩展jQuery,一种方法是直接给属性名赋值$.youname = function(){...},另一种方法是使用$.extend({yourname:function(){...}}),使用哪种看个人喜好。
对于$("selector").NPScrollLoad()这种方式,扩展就不是jQuery本身了,而是jQuery.fn:
方法1:
方法2:
和全局级别的插件方法区别就是扩展的时$.fn而不是$。
因为各式各样的插件很多,属性重名的概率很高,为了避免这样那样的问题,我们使用闭包来写插件,从而使插件的变量和function和其他的不互相影响,这个我尽量简化:
1 ;(function($) { 2 // jQuery扩展 3 $.youname = function([args]) { 4 // TODO 5 }; 6 // 或者 7 $.extend({ 8 youname : function() { 9 // TODO 10 } 11 }); 12 13 // jQuery对象扩展 14 $.fn.youname = function([args]) { 15 // TODO 16 }; 17 // 或者 18 $.fn.extend({ 19 youname : function() { 20 // TODO 21 } 22 }); 23 }) (jQuery);
为什么要这样写?看下面的例子你就明白了:
这个其实就相当于我们直接执行一个匿名函数,并且传递给他一个参数,比如上面的例子就是,我们定义了一个匿名函数用来alert传进去的参数,然后我们给它传递"hello!",它就会马上执行,把插件的相关方法写到这里面并且引入这个js文件的话也就会在第一时间把我们的插件扩展到jQuery上,从而可以直接使用,并且可以保护我们的代码不受外面代码影响,也不会污染其他的代码。为了防止以后压缩代码的时候出错,所以最好在前后都加上一个分号";"。
为了让我们的插件足够通用,我们需要把一些配置留给用户自己定义,通用的做法是使用一个对象来承载所有的设置项,并给他们默认值。
1 var defaults = { 2 msg1: "hello1", 3 msg2: "hello2" 4 }
然后我们给我们的插件函数加上参数:
1 ;(function($) { 2 var defaults = { 3 msg1: "hello1", 4 msg2: "hello2" 5 }; 6 7 $.NPScrollLoad = function(options) { 8 var opts = $.extend(defaults, options); 9 alert(opts.msg1 + opts.msg2); 10 }; 11 12 }) (jQuery);
然后就可以调用了
$.NPScrollLoad({msg1 : "你好"}); $.NPScrollLoad({msg1 : "你好", msg2 : "呵呵"}); $.NPScrollLoad({msg2 : "......"}); $.NPScrollLoad();
没有赋值的属性会使用defaults里面定义的默认值,赋值的属性则会覆盖defaults中相应的属性。
下面是我写的插件代码,代码有些地方比较拙劣,懒得设计和修改了。。。
1 /** 2 * 无限滚动 3 * 作者:Null Pointer 4 */ 5 ;(function($) { 6 $.NPScrollLoad = function(options) { 7 // var opts = $.extend($.NPScrollLoad.defaults, options); 8 $.NPScrollLoad.defaults = $.extend($.NPScrollLoad.defaults, options); 9 return $(window).scroll(function() { 10 processor.process(); 11 }); 12 }; 13 14 var processor = { 15 timeoutId: null, 16 process: function () { 17 clearTimeout(this.timeoutId); 18 this.timeoutId = setTimeout(function () { 19 loadData(); 20 }, 400); 21 } 22 }; 23 24 /** 25 * 加载数据 26 */ 27 function loadData() { 28 if (($(document).height() - ($(document).scrollTop() + $(window).height())) <= $.NPScrollLoad.defaults.offsetPixelToLoad) { 29 $(window).unbind("scroll"); 30 $.NPScrollLoad.preLoad(); 31 $.post( 32 $.NPScrollLoad.defaults.url, 33 { pageIndex : $.NPScrollLoad.defaults.pageIndex }, 34 function (data) { 35 $.each(data, function (i, item) { 36 $.NPScrollLoad.handleResult(item); 37 }); 38 $.NPScrollLoad.afterLoad(); 39 $.NPScrollLoad.defaults.pageIndex++; 40 if (data.length < $.NPScrollLoad.defaults.pageSize) { 41 $.NPScrollLoad.noMoreData(); 42 } else if ($.NPScrollLoad.defaults.pageIndex == $.NPScrollLoad.defaults.maxPage) { 43 $.NPScrollLoad.reachMaxPage(); 44 } else { 45 $(window).bind("scroll", processor.process) 46 } 47 } 48 ); 49 } 50 }; 51 52 53 /** 54 * 处理 55 */ 56 $.NPScrollLoad.handleResult = function(jsonItem) { 57 58 }; 59 60 /** 61 * 加载之前 62 */ 63 $.NPScrollLoad.preLoad = function() { 64 $("#loading").fadeIn(); 65 }; 66 67 /** 68 * 加载之后 69 */ 70 $.NPScrollLoad.afterLoad = function() { 71 $("#loading").fadeOut(); 72 }; 73 74 /** 75 * 无更多数据 76 */ 77 $.NPScrollLoad.noMoreData = function() { 78 $("#nomoreresult").fadeIn(); 79 }; 80 81 /** 82 * 到达最大页数 83 */ 84 $.NPScrollLoad.reachMaxPage = function() { 85 $("#loadmore").show(); 86 }; 87 88 $.NPScrollLoad.defaults = { 89 /* 距离底部距离(开始加载数据) */ 90 offsetPixelToLoad : 100, 91 url : "", 92 pageSize : 10, 93 maxPage : 5, 94 pageIndex : 1 95 }; 96 97 })(jQuery);
代码中有一部分是我之前没有说到的细节:
1.我把defaults定义成$.NPScrollLoad.defaults这样用户可以在外部直接设置默认值,比如$.NPScrollLoad.defaults.url = "text.aspx";这样就行了。
2.在(function($){})(jQuery)内部定义的function是私有的,只有此function内可以访问,比如loadData就只可以在此匿名函数内部访问。
3.我把部分function写成jQuery的扩展,用户就可以在外部访问,或者自定义,比如$.NPScrollLoad.handleResult这样就可以间接实现类似于函数重写的功能,让用户自定义部分操作。
4.第九行我加了一个return,这里是为了延续jQuery的链式调用,比如$("selector").val("abc").attr("id", "aaa")。。。。因为jQuery的函数本身都是返回自身的,所以$(window).scroll()也会返回$(window),所以最后的return可以延续其链式调用特性,不过,因为我写的是全局扩展,所以也就谈不上链式调用了。。。这个对于对象扩展还是有一定重要性的。
5.定义processor对象是因为实时监听scroll事件灰常消耗资源,没滑过1px都会触发事件,所以加个延迟时间,让其一定时间内如果触发的话就取消前一次事件。代码应该不难理解。
下面是调用代码:
1 <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.10.2.min.js"></script> 2 <script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery.NPScrollLoad.1.0.js"></script> 3 <script type="text/javascript"> 4 $(function() { 5 var contextPath = "${pageContext.request.contextPath}"; 6 $.NPScrollLoad({url:contextPath + "/ajaxPage/home"}); 7 }); 8 </script>
本来还想排版,这么晚了,算了,睡觉了。