jQuery插件防冲突原理

来源:互联网 发布:数据库的设计原则 编辑:程序博客网 时间:2024/06/05 07:21

说到jQuery插件,bootstrap的jQuery插件名声在外,当然主要原因是bootstrap框架被很多人喜爱,学习,并不是因为他的js插件功能强大,比它强大好用的jQuery很多!不过对于插件,眼前成熟做法都会在结尾那里加上防止变量名冲突,也就是不要让别的插件覆盖自己插件,导致程序出错。

最开始便是jQuery的noConflict()函数,之后大部分插件都会加上这个函数。很多人可能会问,加上这个有什么用?全局变量名冲突,换个名字咯,也可以搞个很长的组合变量名字。嗯,想法不错。长名字固然在很大概率上避免名字冲突,可缺点就是不好记,使用麻烦。而且长名字并不是不会重名,随着javascript开发企业级项目的兴起,javascript代码动辄上千行,为了高效率开发,使用各种js库,框架是不可少。用的多,自然就无法避免插件冲突。

言归正传,我们回顾下jQuery插件有那几个特征:

  1. 通过$.extend()来扩展jQuery
  2. 通过$.fn 向jQuery添加新的方法
  3. 通过$.widget()应用jQuery UI的部件工厂方式创建

只要是jQuery插件,自然都会使用到以上3种方法,为jQuery添加自定义函数,常用的就是$.fn和$.extend  成员方法和静态方法。而jQuery插件防冲突,就是利用jQuery为桥梁,进行方法名的复写。

首先,我们定义一个简单jQuery插件
(function($){          $.fn.ct=function(){            alert("自定义冲突插件");         }})(jQuery);

然后再次定义一个插件
+(function($){       $.fn.ct=function(){           alert("自定义第二个冲突插件");       }})(jQuery);

给个Dom元素input按钮,用来测试用。
<input id="btn" type="button" value="按钮" />

接下来就调用插件往jQuery上添加的成员函数ct()
$(function(){$.fn.ct.noConflict();$('#btn').ct();//输出:自定义第二个冲突插件});

由于两个jQuery插件都往jQuery对象中添加了ct()同名函数,根据javascript的解析规则,后面的会覆盖前面相同名字的函数,所以输出第二个。那如果想输出第一个插件,怎么办?最麻烦有效的就是,修改函数名,把第一个改成其它名字。很好,这确实解决了当前问题,但如果还有其它名字插件时候呢?会不会和你现在改的名字冲突?所以我们迫切需要一种解决方案,释放当前函数名就应运而生!
我们来修改下第二个插件
+(function($){var old=$.fn.ct;//保存可能冲突的重名函数        $.fn.ct=function(){            alert("自定义第二个冲突插件");        }        //防冲突主体函数        $.fn.ct.noConflict=function(){            $.fn.ct=old;            return this;        }})(jQuery);

第一个变量名,大家如果看过bootstrap的插件源码,一定很熟悉。old是保存可能存在的同名函数(方法),当该插件上面已经出现过同名函数,那么old就可以保存,然后
$.fn.ct.noConflict()
重写$.fn.ct函数,此时该函数就不再是第二个插件的函数了,而是第一个插件的同名函数。所以我们再修改下调用函数,就可以输出我们第一个插件内容
$(function(){$.fn.ct.noConflict();//重写$.fn.ct函数$('#btn').ct();//输出:自定义冲突插件});
我们想要输出第一个插件内容目的达到了。让我们举一反三,加入我要同时使用两种插件,怎么办?由于上面例子都是往jQuery上添加函数重名,而javascript没有重载函数,那么我们要保证函数名不能一样,否则无法逃脱插件定义函数被重写命运。
还是第二个插件,再次修改如下
+(function($){var old=$.fn.ct;//保存可能冲突的重名函数     $.fn.ct2=$.fn.ct=function(){          alert("自定义第二个冲突插件");     }     //防冲突主体函数     $.fn.ct.noConflict=function(){          $.fn.ct=old;          return this;     }})(jQuery);

我们添加新的函数ct2()它和ct()是一样的,所以我们在释放ct()时候,仍然可以通过ct2调用第二个插件,这和jQuery调用一样原理,一个对象保存两个对象名,当$冲突,jQuery还可以使用。
$(function(){$.fn.ct.noConflict();$('#btn').ct();//输出 自定义冲突插件$('#btn').ct2();//输出自定义第二个冲突插件});

或许有人又要说了,当项目中某一部分功能,既不需要ct也不需要ct2怎么办,意思就是我不需要使用第二个插件了,但项目文件其它部分已经引用了第二个插件。那好,我们就添加一个判断,当两种情况存在,就重写两个函数。
+(function($){var old=$.fn.ct;//保存可能冲突的重名函数var old2=$.fn.ct2;        $.fn.ct2=$.fn.ct=function(){            alert("自定义第二个冲突插件");        }        //防冲突主体函数        $.fn.ct.noConflict=function(){            if(old){            $.fn.ct=old;            }else if(old&&old2){            $.fn.ct=old;            $.fn.ct2=old2;            }            return this;            }})(jQuery);

这种写法依旧有问题,有人说,我们在jQuery对象中添加两个同样功能的函数。是的,这里针对的是jQuery插件,该方法未必有用,略显多余,但原理值得学习。就和jQuery源码中出现的代码
window.jQuery = window.$ = jQuery;
它为jQuery插件注册两个全局变量$和jQuery,这里一样有两个一样的对象。所以,万事万物都不可能完美,上面的防冲突就是这样。

为了避免插件冲突,我们命名时候要考虑方便记忆,方便推广,符合命名规范。

给个最终版本案例代码
<!DOCTYPE html><html lang="en"><head><meta charset="UTF-8"><title>jQuery插件防冲突</title><script src="http://libs.baidu.com/jquery/1.11.1/jquery.js"></script></head><body><input id="btn" type="button" value="按钮" /><script type="text/javascript">+(function($){            $.fn.ct=function(){                alert("自定义冲突插件");            }})(jQuery);+(function($){var old=$.fn.ct;//保存可能冲突的重名函数var old2=$.fn.ct2;            $.fn.ct2=$.fn.ct=function(){                alert("自定义第二个冲突插件");            }            //防冲突主体函数            $.fn.ct.noConflict=function(){            if(old){            $.fn.ct=old;            }else if(old&&old2){            $.fn.ct=old;            $.fn.ct2=old2;            }            return this;            }})(jQuery);$(function(){$.fn.ct.noConflict();$('#btn').ct();$('#btn').ct2();});</script></body></html>