JavaScript 是一门混乱的语言,好的特性和坏的特性混杂在一起。而不同浏览器对标准的解析不一致,使得这门语言更加混乱,在这种情况下遵循最佳实践有诸多好处,至少不会掉入坑里。所以就有了《JavaScript: The Good Parts》这类书专门教最佳实践。可惜读完后再去看别人的 js 代码,会发觉几乎没有谁做得很标准。

一、jQuery 插件的类别

在 jQuery 中要使用一个插件,一般有两种形式:

  • 类级别。例如 $.myPlugin()
  • 对象级别。例如 $('#node').myPlugin()

类级别插件可以理解为拓展 jQuery 类,即给 jQuery 添加新的全局函数,典型的例子就是 $.ajax() 这个函数。jQuery 的全局函数就是属于 jQuery 命名空间的函数。另一种是对象级别的插件,即作用于指定的 jQuery 对象,典型的例子 $('.msg').show()

二、类级别 jQuery 插件的开发

1. 原始写法

一般在项目中我们会引入一个 js 文件,里面存放了所有的 js 代码。

<script type="text/javascript" src="http://www.lovelucy.info/all.js"></script>

只要写一些函数简单地放在文件里,就算是一个模块,直接调用就行了。

   function m1(){
    //...
  }
  function m2(){
    //...
  }

这种方法缺陷很明显,就是污染了全局空间,无法保证不与其他模块发生变量名冲突,而且方法成员之间看不出直接关系。

2. 扩展写法

使用 jQuery.extend(object) 来扩展 jQuery 类本身,可以理解为 jQuery 添加静态方法。

$.extend({
  addMethod : function(a, b){return a + b;}
});
// $.addMethod(1, 2); //return 3

3. 简单写法

给 jQuery 添加一个全局函数,只需如下定义

jQuery.foo = function() {
alert('test');
// other code...
};

这样就能直接用了:jQuery.foo() 或者 $.foo() 。

4. 使用命名空间

虽然上面的 2 种写法相对于原始写法要干净很多,减少了在全局空间冲突的概率,但是在 jQuery 命名空间中,仍然不可避免某些函数或变量名可能和其他 jQuery 插件冲突。因此我们习惯再封装一层,将一些方法封装到另一个自定义的命名空间。

jQuery.myPlugin = {
foo:function() {
alert('test');
},
bar:function(param) {
alert('test "' + param + '".');
}
};
// $.myPlugin.foo();
// $.myPlugin.bar('hello');

采用命名空间的函数仍然是全局函数,使用独立的插件名我们可以避免命名空间内函数的冲突。

三、对象级别 jQuery 插件的开发

大部分 jQuery 插件都是对象级别的,开发一个对象级别插件会遇到闭包这个概念,简单起见先只看闭包的表现形式

(function($){
// your codes
})(jQuery);

1. 扩展写法

给 jQuery 对象添加方法,就是对 jQuery.prototype 进行扩展,为 jQuery 类添加成员方法,需要用到jQuery.fn.extend(object); 。下面是一个例子:

$.fn.extend({
getInputText:function(){
$(this).click(function(){
alert($(this).val());
});
}
});
//$("#username").getInputText();

2. 通用写法

对象级别的插件也可以这样定义 $.fn.myPlugin = function(){},同样的,和类级别相比多了一个 fn。

一个通用的对象级别插件框架——

(function($){
$.fn.myPluginName = function(options){
var defaults = {} //各种属性和参数
var options = $.extend(defaults, options);
this.each(function(){
//插件的实现代码
});
};
})(jQuery);

$.extend(defaults, options) 通过合并 defaults 和 options 来扩展默认参数,实现插件接受外部 options 参数的功能。于是我们就可以见到这样的用法:

$('#myDiv').hilight({
foreground: 'blue'
});

3. 改进的通用写法

上面代码的一种改进是暴露插件的默认设置。这可以让插件的使用者更容易用较少的代码覆盖和修改插件。

(function($){
$.fn.myPluginName = function(options){
var options = $.extend({}, $.fn.myPluginName.defaults, options);
this.each(function(){
//插件的实现代码
});
};
// 暴露的默认参数
$.fn.myPluginName.defaults = {};
})(jQuery);

于是我们就可以见到这样使用的

$.fn.hilight.defaults.foreground = 'blue';
$('#myDiv').hilight();

覆盖默认的配置就只需要调用一次,而不必在每次调用插件时都传递参数。是否需要传递参数,在不同的场景下可以灵活处理,两者的使用可以结合起来。

更高级的插件写法还包括暴露一些函数给使用者,让他们可以覆盖。另一方面,也可以保持私有函数的私有性。具体的代码这里就不多赘述了。学习的最好方式就是阅读别人的插件代码。

jQuery插件的种类

编写插件的目的是给已有的一系列方法或函数做一个封装,以便在其他地方重复使用,方便后期维护和提高开发效率。jQuery的插件主要分为以下三种类型:

1.封装对象方法的插件

这种插件是将对象方法封装起来,用于对通过选择器获取的jQuery对象进行操作,是一种最常见的插件。绝大部分的jQuery插件都是封装对象方法的插件。此类插件可以发挥出jQuery的强大优势。

2.封装全局函数的插件

可以将独立的函数加到jQuery命名空间之下。例如noConflict()方法是jQuery内部作为全局函数的插件附加到内核上去的。

3.选择器插件

极少数的情况下,需要用到选择器插件。虽然jQuery的选择器十分强大,但还是会需要扩充一些适用的选择器。

jQuery插件的基本要点

(1)jQuery插件的文件名推荐命名为jquery.[插件名].js,以免和其他JavaScript库插件混淆。

(2)所有对象方法都应该附加到jQuery.fn对象上,所有的全局函数都应当附加到jQuery对象本身上。

(3)插件内部,this指向的是当前通过选择器获取的jQuery对象,对于一般的方法,内部的this指向的是DOM元素。

(4)可以通过this.each来遍历所有元素。

(5)所有的方法或函数插件,都应当以分号结尾,否则压缩的时候可能出现问题。为了更稳妥些,甚至可以在插件头部先加上一个分号,以免他人的不规范的代码给插件带来影响。

(6)通常情况下,插件应该返回一个jQuery对象,以保证插件能够链式操作。

(7)避免在插件内部使用$作为jQuery对象的别名,而应使用完整的jQuery来表示,这样可以避免冲突。当然可以用笔包这种技巧来回避这个问题,使插件内部继续使用$作为jQuery的别名。常见的jQuery插件的结构如下:

[javascript] view plaincopyprint?

  1. //为了更好的兼容性,开始前加分号
  2. ;(function($){
  3. /*这里放置代码,可以使用$作为jQuery对象别名*/
  4. })(jQuery);//这里将jQuery作为实参传递给匿名函数

jQuery插件的机制

jQuery提供了两个用于扩展jQuery功能的方法,即jQuery.fn.extend()方法和jQuery.extend()方法。这两个方法都接受一个参数,类型为Object。Object的”键/值对”分别代表“函数方法名/函数主体”。

1.jQuery.extend()

可以用于扩展后两种插件。该方法是对jQuery对象的扩展,可以理解为静态方法,不需要实例jQuery就可以使用,代码如下:

[javascript] view plaincopyprint?

  1. jQuery.extend({
  2. add : function(a, b){
  3. return a + b;
  4. }
  5. });
  6. alert($.add(2, 3)); //7

jQuery.extend()方法除了可以用于扩展jQuery对象之外,还能用于扩展已有的Object对象。如合并settings对象和options对象,修改并返回settings对象,代码如下:

[javascript] view plaincopyprint?

  1. var defaults = {name:'ZhangSan', sex:'男', age:20};
  2. var options = {name:'LiSi', age:22};
  3. var newOpts = $.extend(defaults, options);
  4. //结果newOpts = {name:'LiSi', sex:'男', age:22};

2.jQuery.fn.extend()

用于扩展之前提到的三种类型插件中的第一种。该方法是对jQuery元素的扩展,只能用在jQuery元素上,可以理解为普通方法,即获取了相应的jQuery对象才能调用。定义插件时需要返回this,以支持jQuery的链式操作,代码如下:

[javascript] view plaincopyprint?

  1. $.fn.extend({
  2. color : function(c){
  3. this.css("color", c);
  4. }
  5. });
  6. alert($('#test').color('red'));

编写jQuery插件

常见jQuery插件的结构如下:

[javascript] view plaincopyprint?

  1. ;(function($){
  2. //这里编写插件的代码,可以继续使用$作为jQuery的别名
  3. //定义一个局部变量foo,仅方法内部可以访问
  4. var foo;
  5. var bar = function(){
  6. /*
  7. 在匿名函数内部的函数都可以访问foo,即使在外部调
  8. 用bar()的时候,也可以在bar()的内部访问foo,但
  9. 无法在匿名函数外部直接访问foo
  10. */
  11. }
  12. /*
  13. 下面的语句让匿名函数内部的函数bar()逃逸到全局可访问的范围,
  14. 这样就可以在匿名函数的外部通过$.BAR()来访问内部定义的函数
  15. bar(),并且内部函数bar()也能访问foo
  16. */
  17. $.BAR = bar;
  18. })(jQuery);

1.封装jQuery对象方法的插件

这里主要是为了说明编写jQuery插件的过程和注意事项,就以一个简单的实例(设置和获取颜色)来说明。

1)插件功能说明

(1)设置匹配元素的颜色。

(2)获取匹配元素的颜色。

2)将该插件按规范命名为jquery.color.js。

3)在JS文件中搭好框架,由于是对jQuery对象的方法扩展,因此采用扩展插件方法jQuery.fn.extend()来编写,代码如下:

[javascript] view plaincopyprint?

  1. ;(function($){
  2. $.fn.extend({
  3. color : function(c){
  4. //这里写插件的代码
  5. }
  6. });
  7. })(jQuery);

4)编写插件的实现代码如下:

[javascript] view plaincopyprint?

  1. ;(function($){
  2. $.fn.extend({
  3. color : function(c){
  4. if(c == undefined){//如果不传值,则获取字体颜色
  5. return this.css("color");
  6. } else { //如果传值,则设置字体颜色
  7. return this.css("color", c);
  8. }
  9. }
  10. });
  11. })(jQuery);

这样,一个简单的jQuery插件算是完成了。

2.封装全局函数的插件

这类插件是在jQuery命名空间内部添加一个函数。这类插件只是普通的函数。

例如新增两个函数,分别用于去除左侧和右侧的空格,代码如下:

[javascript] view plaincopyprint?

  1. ;(function($){
  2. $.extend({
  3. ltrim : function(text){
  4. return (text || "").replace(/^\s+/g, "");
  5. },
  6. rtrim : function(text){
  7. return (text || "").replace(/\s+$/g, "");
  8. }
  9. //(text || "")部分是用于放置传递进来的text这个字符串变量是未定义的状态
  10. //当text是undified,则返回字符串"",否则返回字符串text
  11. });
  12. })(jQuery);

最新文章

  1. asp.net web api 的版本升级到 2.2的记录
  2. 【代码笔记】iOS-书架页面
  3. struts1 核心类
  4. ShortestPath:Wormholes(POJ 3259)
  5. hdu 1806 rmq
  6. Java学习-014-文本文件写入实例源代码(两种写入方式)
  7. HDU4288:Coder(线段树单点更新版 &amp;&amp; 暴力版)
  8. mysql修改列名和列类型
  9. 怎么删除远程登录连接的ip
  10. Sqlite事物与锁
  11. JAVA 鲜为人知的二次标记 第六节
  12. SDWEBImage和collectionView的组合,以及collectionView的随意间距设置
  13. 从零部署Spring boot项目到云服务器(正式部署)
  14. Java_异常以及处理
  15. javascript中数组化的一般见解
  16. 24)django-信号
  17. Confluence 6 用户提交的备份和恢复脚本
  18. 关于IDEA每次修改HTML,Css等静态资源文件都需要重启的设置修改
  19. cdnbest设置301跳转
  20. Angular2入门:TypeScript的类型 - 对象解构

热门文章

  1. extern &quot;C&quot;解析
  2. (6)centos安装和解压
  3. TensorFlow——共享变量的使用方法
  4. Fennec VS. Snuke --AtCoder
  5. 记录一次(xheditor-1.1.6-zh-cn.min.js)的错误:Cannot read property &#39;match&#39; of undefined的问题解决
  6. Andriod Atom x86模拟器启动报错
  7. ReactiveCocoa 迎接下一个更加美好的世界
  8. python traceback学习(转)
  9. k8s学习(一)——kubectl与api-server之间的交互核心过程
  10. JS门面模式