作为一个菜鸟,最近学习了一下Jquery插件开发,写完一个练手的插件之后发现在Jquery上开发插件实在是很令人愉悦。Jquery插件分为两种,一种是类级别的,另一种是对象级别的。由于这篇文章里我学习的是对象级别的,所以本文主要记录对象级别插件开发。
首先插件开发需要对Jquery的fn进行扩展,一般采取下述几种方式之一

//方式一
jQuery.fn.myPlugin = function() {
    //我们的代码
};

//方式二
$.fn.myPlugin = function() {
    //我们的代码
};

//方式三
jQuery.fn.extend({     
    myPlugin:function(){     
        //我们的代码       
    }     
});

//方式四
$.fn.extend({     
    myPlugin:function(){     
        //我们的代码       
    }     
})

这里面的$符号其实就是变量jQuery的一个别名而已,另外,我们可以使用extend方法来扩展fn,也可以直接在fn上定义新的对象。除此之外,我们还需要把插件封装起来,防止插件的代码污染其他逻辑代码,所以使用一个匿名函数来做这件事情

(function( $ ) {
  $.fn.myPlugin = function() {
    // 我们的代码
  };
})( jQuery );

这样我们就可以使用$(“somediv”).myPlugin()来使用这个插件了。为了能够让插件有多个方法可用,那么可以使用如下方式来组织代码

(function( $ ){

  var methods = {
    init : function( options ) { 
      // 代码
    },
    show : function( ) {
      // 代码
    },
    hide : function( ) { 
      // 代码
    },
    update : function( content ) { 
      // 代码 
    }
  };

  $.fn.myPlugin = function( method ) {
    
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist' );
    }    
  
  };

})( jQuery );

//可以使用如下方式来调用
$("somediv").myPlugin({...}); //调用了init方法
$("somediv").myPlugin("update",{...});//调用了update方法

代码会首先判断调用者传入的第一个参数所对应的函数名在不在定义的函数哈希里,在的话使用apply方法调用该函数,并把被调用函数的this设置为当前this,同时把剩余的参数传给被调用的函数。如果第一个参数是一个对象或者为空,那么同样使用apply调用init初始化方法。
在插件运行过程中,如果有数据需要存储,比如上例中的options需要存储起来,供插件运行时其他方法使用,那么我们最好使用jquery的data方法来管理。

(function( $ ){

  var methods = {
    init : function( options ) { 
      // 这里存储数据
      $(this).data("mydata", options);
      // 其他代码
    },
    show : function( ) {
      // 这里使用数据
      var myData = $(this).data("mydata");
      //其他代码
    },
    hide : function( ) { 
      // 代码
    },
    update : function( content ) { 
      // 代码 
    }
  };

  $.fn.myPlugin = function( method ) {
    
    if ( methods[method] ) {
      return methods[ method ].apply( this, Array.prototype.slice.call( arguments, 1 ));
    } else if ( typeof method === 'object' || ! method ) {
      return methods.init.apply( this, arguments );
    } else {
      $.error( 'Method ' +  method + ' does not exist' );
    }    
  
  };

})( jQuery );

最后放上练手的例子,一个可以点击表头排序的表格插件

(function($) {
	var arrowUp = "▲", arrowDown = "▼";
	var sortArray = function(arr, sortBy, order) {
		var sortFunc = function(a, b) {
			if (order === "desc") {
				console.log(typeof a[sortBy]);
				if (typeof a[sortBy] === "string" && typeof b[sortBy] === "string") {
					return a[sortBy].localeCompare(b[sortBy]);
				} else {
					return b[sortBy] - a[sortBy];
				}
			} else {
				if (typeof a[sortBy] === "string" && typeof b[sortBy] === "string") {
						return b[sortBy].localeCompare(a[sortBy]);
				} else {
					return a[sortBy] - b[sortBy];
				}
			}
		};
		return arr.sort(sortFunc);
	};
	var drawBody = function(options){
		var dCount = 0, ddCount = 0;
		dCount = options["data"].length;
		ddCount = options["data"][0].length;
		var htm = [];
		for (var i = 0; i < dCount; i++) {
			htm.push("<tr>");
			for (var j = 0; j < ddCount; j++) {
				htm.push("<td>");
				htm.push(options["data"][i][j]);
				htm.push("</td>");
			}
			htm.push("</tr>");
		}
		var htmStr = htm.join("");
		$(this).find("div > table > tbody").html(htmStr);
	};
	var methods = {
		"init" : function(opts) {
			var options = $.extend({
				"thead" : ["c1", "c2"],
				"data" : [[1, 2], [3, 4],[5, 3]],
				"sortBy": 1,
				"order" : "desc"
			},opts);
			var headStr = "";
			cCount = options.thead.length;
			var colWidthAll = 100 / cCount;
			for (var i = 0; i < cCount; i++) {
				var arrow = "";
				if (options.sortBy === i) {
					if (options.order === "desc") {
						arrow = arrowDown;
					} else {
						arrow = arrowUp;
					}
				}
				var thWidth = "";
				if (options.colWidth) {
					if (options.colWidth[i]) {
						thWidth = "width='" + options.colWidth[i] + "'";
					}
				} else {
					thWidth = "width='" + colWidthAll + "%'"
				}
				headStr += "<th " + thWidth + "><span rel='" + i + "'>" + options.thead[i] 
						+ " <span>" + arrow + "</span></span></th>";
			}
			var tableStr = "<div class='sGrid_wrap'><table class='sGrid'>"
								+"<thead><tr>"
								+ headStr
								+"</tr></thead>"
								+"<tbody></tbody>"
							+"</table></div>";
			$(this).html(tableStr);
			
			options["data"] = sortArray(options["data"], options["sortBy"], options["order"]);
			drawBody.apply(this, [options]);
			var me = $(this);
			$(this).find("div > table > thead th span").click(function(){
				var c = $(this).attr("rel");
				if (c == options.sortBy) {
					if (options.order === "desc"){
						options.order = "asc";
						$(this).find("span").html(arrowUp);
					} else {
						options.order = "desc";
						$(this).find("span").html(arrowDown);
					}
				} else {
					me.find("div > table > thead th span span").html("");
					options.sortBy = c;
					options.order = "desc";
					$(this).find("span").html(arrowDown);
				}
				options["data"] = sortArray(options["data"], options["sortBy"], options["order"]);
				drawBody.apply(me, [options]);
			});
		}
	};
	$.fn.rankTable = function(method) {
		if ( methods[method] ) {
      		return methods[method].apply( this, Array.prototype.slice.call( arguments, 1 ));
    	} else if ( typeof method === 'object' || ! method ) {
      		return methods.init.apply( this, arguments );
    	} else {
      		$.error( 'Method ' +  method + ' does not exist' );
    	}
	};
})(jQuery);
//调用方式
<html xmlns="http://www.w3.org/1999/xhtml">  
<head>
    <meta http-equiv="content-type" content="text/html;charset=utf-8">
    <title>rankTable</title>
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js" type="text/javascript"></script> 
    <script src="jquery.ranktable.js" type="text/javascript"></script>
    <link href="style.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript">
        $(function () {
            $("#rank_table").rankTable({
                "thead" : ["姓名", "年龄", "成绩"],
                "data" : [["张三", 16, 98], ["李四", 15, 88], ["王五", 18, 100], ["孙六", 17, 60]],
                "sortBy": 2,
                "order" : "desc",
                "colWidth" : ["33%","33%"]
            });

        });  
    </script>  
</head>  
<body> 
    <div id="rank_table">  
    </div>
</body>  
</html>