一个基本的函数可能在某些情况下可以良好地工作,但是一个稍微复杂一点的插件就需要提供各种各样的方法和私有函数。你可能会使用不同的命名空间去为你的插件提供各种方法,但是最好不要让你的源代码因为多余的命名空间而变得混乱。
下面的代码定义了一个存储公有方法的JSON对象,以及展示了如何使用插件中的主函数中去判断哪些方法被调用,和如何在让方法作用到选择器每个元素上。
(function($) { // 在我们插件容器内,创造一个公共变量来构建一个私有方法 var privateFunction = function() { // code here } // 通过字面量创造一个对象,存储我们需要的共有方法 var methods = { // 在字面量对象中定义每个单独的方法 init: function() { // 为了更好的灵活性,对来自主函数,并进入每个方法中的选择器其中的每个单独的元素都执行代码 return this.each(function() { // 为每个独立的元素创建一个jQuery对象 var $this = $(this); // 执行代码 // 例如: privateFunction(); }); }, destroy: function() { // 对选择器每个元素都执行方法 return this.each(function() { // 执行代码 }); } }; $.fn.pluginName = function() { // 获取我们的方法,遗憾的是,如果我们用function(method){}来实现,这样会毁掉一切的 var method = arguments[0]; // 检验方法是否存在 if(methods[method]) { // 如果方法存在,存储起来以便使用 // 注意:我这样做是为了等下更方便地使用each() method = methods[method]; // 如果方法不存在,检验对象是否为一个对象(JSON对象)或者method方法没有被传入 } else if( typeof(method) == 'object' || !method ) { // 如果我们传入的是一个对象参数,或者根本没有参数,init方法会被调用 method = methods.init; } else { // 如果方法不存在或者参数没传入,则报出错误。需要调用的方法没有被正确调用 $.error( 'Method ' + method + ' does not exist on jQuery.pluginName' ); return this; } // 调用我们选中的方法 // 再一次注意我们是如何将each()从这里转移到每个单独的方法上的 return method.call(this); } })(jQuery);
注意我把 privateFunction 当做了一个函数内部的全局变量。考虑到所有的代码的运行都是在插件容器内进行的,所以这种做法是可以被接受的,因为它只在插件的作用域中可用。在插件中的主函数中,我检验了传入参数所指向的方法是否存在。如果方法不存在或者传入的是参数为对象, init 方法会被运行。最后,如果传入的参数不是一个对象而是一个不存在的方法,我们会报出一个错误信息。
同样要注意的是,我是如何在每个方法中都使用 this.each() 的。当我们在主函数中调用 method.call(this) 的时候,这里的 this 事实上就是一个jQuery对象,作为 this 传入每个方法中。所以在我们方法的即时作用域中,它已经是一个jQuery对象。只有在被 each()所调用的函数中,我们才有必要将this包装在一个jQuery对象中。
下面是一些用法的例子:
/* 注意这些例子可以在目前的插件代码中正确运行,并不是所有的插件都使用同样的代码结构 */ // 为每个类名为 ".className" 的元素执行init方法 $('.className').pluginName(); $('.className').pluginName('init'); $('.className').pluginName('init', {}); // 向init方法传入“{}”对象作为函数参数 $('.className').pluginName({}); // 向init方法传入“{}”对象作为函数参数 // 为每个类名为 “.className” 的元素执行destroy方法 $('.className').pluginName('destroy'); $('.className').pluginName('destroy', {}); // 向destroy方法传入“{}”对象作为函数参数 // 所有代码都可以正常运行 $('.className').pluginName('init', 'argument1', 'argument2'); // 把 "argument 1" 和 "argument 2" 传入 "init" // 不正确的使用 $('.className').pluginName('nonexistantMethod'); $('.className').pluginName('nonexistantMethod', {}); $('.className').pluginName('argument 1'); // 会尝试调用 "argument 1" 方法 $('.className').pluginName('argument 1', 'argument 2'); // 会尝试调用 "argument 1" ,“argument 2”方法 $('.className').pluginName('privateFunction'); // 'privateFunction' 不是一个方法
在上面的例子中多次出现了 {} ,表示的是传入方法中的参数。在这小节中,上面代码可以可以正常运行,但是参数不会被传入方法中。继续阅读下一小节,你会知道如何向方法传入参数。 设置插件:传入参数 许多插件都支持参数传入,如配置参数和回调函数。你可以通过传入JS键值对对象或者函数参数,为方法提供信息。如果你的方法支持多于一个或两个参数,那么没有比传入对象参数更恰当的方式。