jQuery 的插件开发模式主要有三种:javascript
这里咱们选用第二种:css
$.fn.myplugin = functin() { // plugin code }
由于这种方法是加在jQuery对象上,能够在jQuery选择器选择元素后直接调用:html
$('body').myplugin();
若对其余两种方法有兴趣,请自行查看jQuery 官方文档。java
改变元素的背景颜色插件:jquery
$.fn.tinyPlugin = function(){ this.css('background-color','#fff'); // 这里的this是jQuery对象,而不是原生的js对象 }
这样写的话,颜色不能使用时定义,修改一下:git
$.fn.tinyPlugin = function(bg){ this.css('background-color',bg); }
以上是一个jQuery插件的基本结构。但编写更复杂的jQuery插件,借助面向对象的思想可使插件具备更好的扩展性、可维护性。github
1.建立myplugin构造函数segmentfault
2.定义myplugin的方法api
3.添加到jQuery对象中缓存
首先将代码放到一个自执行的匿名函数中,防止全局对象污染:
根据上面的步骤,基本结构大体以下:
// 定义构造函数 function myplugin($element,options){ // ... } // 添加方法 myplugin.prototype = { method1: function(){ // ... }, method2: function(){ // ... } }; // 添加到jQuery对象中 $.fn.myplugin = function(options){ new myplugin(this,options); }
后面将在这个结构上进行完善:
放到匿名函数内部的主要做用是隔离做用域,避免变量污染,而自执行能够返回须要的函数或对象,而不须要每次经过条件判断为处理,只须要在首次加载的时候赋值给某个变量。更详细的信息参见知乎上的 这个问题。
;(function($){ // ... })(jQuery);
留意到上面,函数前还加了分号,这是因为自执行函数前省略分号的表达式时,某些状况下会报错,能够看 这里。
在匿名函数里面还传入了jQuery对象,这样作的好处是美圆符号 $
在内部是一个私有变量,仅表明jQuery,能够防止和其余使用 $
的库冲突。
有的自执行函数还将window对象、undefined对象传入,具体做用能够看 这里。
options是提供给使用者定义的参数。一个好的插件,应该提供必要的参数给使用者,而且提供好默认的参数,由于不少状况下不是每一个参数都须要自定义。以前在项目中写了一个加载更多 LoadMore
插件,就以这个插件为例:
function LoadMore($element,options){ this.$element = $element; this._defaults = { loadingSelector: ".zc_loading", //加载中的提示 overSelector: ".zc_loaded", // 加载完毕的加载 } this.options = $.extend({},this._defaults,options||{}); // 合并参数 }
通常插件都会有一个 init()
方法,调用插件时作一些初始化操做:
function myplugin($element,options){ this.init(); } // 添加方法 myplugin.prototype = { init: function(){ // ... } };
为了防止用户屡次在同一个元素上调用插件,有必要加一些已初始化的判断。经过在该元素上用 data()
方法缓存插件的实例对象,每次实例化时判断该缓存对象便可。
$.fn.myplugin = function(options){ if (!$.data(this, 'myplugin')) { $.data(this, 'myplugin', new myplugin(this, options)); } }
$
选择器返回的有多是多个元素,所以须要返回的全部元素添加插件,直接使用jQuery自带的 each()
方法:
$.fn.myplugin = function(options){ this.each(function(){ if (!$.data(this, 'myplugin')) { $.data(this, 'myplugin', new myplugin(this, options)); } }); }
注意这里的this
是jQuery对象,而不是原生JS对象。因此能够直接使用this.each()
。
因为jQuery有个链式操做的特性,在每一个方法调用后都会返回该对象,所以只须要 return
该对象便可保持链式操做:
$.fn.myplugin = function(options){ return this.each(function(){ // ... }); }
插件不只有可配置的参数,不少时候还须要调用方法。好比说“加载更多”插件,可能须要知道如今加载到第几页,或者是否已经所有加载完毕。此时就须要调用方法来得到结果。
在前面咱们知道是在 prototype
定义方法:
LoadMore.prototype = { init: function(){}, // 从新加载 reload: function(){}, // 开始加载 startLoad: function(){}, // 本次加载完成 loadOver: function(){}, // 所有加载完毕 allLoadOver: function(){}, // 插入内容 insert: function(content){} }
方法名能够经过options参数传入,只需在内部作字符串判断:
$.fn.LoadMore = function(options,para){ var instance; instance = $.data(this,'LoadMore'); if(!instance){ instance = new LoadMore(this,options); $.data(this,'LoadMore',instance); } // 若是是字符串则调用方法 if($.type(options) === 'string') { return instance[options](para); } return this; // 保持链式 }
所以咱们调用方法能够像下面这样:
$('#list').LoadMore('startLoad');
可是,当调用的方法须要传参怎么办?很简单,那就再加一个参数 para
:
$.fn.LoadMore = function(options,para){ // ... // 若是是字符串则调用方法 if($.type(options) === 'string') { return instance[options](para); } return this; // 保持链式 }
调用带参数的方法:
$('#list').LoadMore('insert','这是待插入的内容');
这里若是要使用回调函数,和上面也是同样的道理,只需在内部加个函数判断。不详述。如有更多的参数,请使用对象 {}
。
在写 LoadMore
插件的过程当中,还发现须要使用事件,好比说滚动到某个位置时,执行某些操做。也很简单,事件咱们能够直接写在配置参数 options 中:
this._defaults = { onScroll: null, // scroll中 onScrollBottom: null // scroll到底部 }
而后在内部 init()
函数中调用前判断:
init: function(){ var that = this, $win = $(window), $doc = $(document); $win.on('scroll',function(){ (typeof that.options['onScroll'] == 'function') && that.options['onScroll'](); if($win.scrollTop() + $win.height() >= $doc.height()-10){ (typeof that.options['onScrollBottom'] == 'function') && that.options['onScrollBottom'](); } }); }
如今流行模块化开发,AMD是require.js在推广过程当中的规范化产出,AMD说明见 这里。
下面的代码可使你的插件兼容AMD规范,能够在require.js中直接调用,固然,没有使用require.js直接 <script>
引入也是能够的。
// amd support (function(factory){ // amd support if(typeof define === 'function' && define.amd){ define(['jquery'],factory); }else { factory(jQuery); } }(function($){ var exports = {}; // 这里写插件代码 return exports; }));
上面的前一段是判断是否有define函数,有则调用define方法定义一个模块,不然直接执行。后一段的 exports
对象是模块的返回对象,模块对外的接口。关于AMD规范的具体信息,可参考阮一峰的 这篇文章。
上面所写的就是写一个插件的大体流程,因为能力有限,还有不少要完善的地方。想要了解更多,这里推荐一篇文章 深刻理解jQuery插件开发。另外,这里提供一个gitHub上面的某位大神写的插件 SlipHover供参考。