jQuery插件防衝突原理

說到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>







發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章