許多的JS架構類庫都選擇使用$符號作為函數或變數名,而且在實際的項目開發中,使用範本語言的話有可能"$"符號即為該範本語言的關鍵字。例如Veclocity範本語言,$是關鍵字.與jQuery一起使用可能會存在衝突(頁面中直接寫jq代碼,引入的js檔案不存在該問題)。吐槽下為啥這麼多js庫喜歡用$($ is money?)。
jQuery是使用$符號作為函數或變數名最為典型的一個。在jQuery中,$符號只是window.jQuery對象的一個引用,因此即使$被刪除,jQuery依然能保證整個類庫的完整性。
jQuery的設計充分考慮了多架構之間的引用衝突。我們可以使用jQuery.noConflict方法來輕鬆實現控制權的轉交。
在論述如何解決jQuery衝突之前,我們有必要先對noConflict函數做一個瞭解,解決衝突的方法就藏在裡面。
jQuery.noConflict
jQuery.noConflict([removeAll]);
預設參數情況下:
運行這個函數將變數$的控制權讓渡給第一個實現它的庫。在運行完這個函數之後,就只能使用jQuery變數訪問jQuery對象(函數不帶參數),例如jQuery("div p")。不過需要注意的是該函數必須在你匯入jQuery檔案之後,並且在匯入另一個導致衝突的庫"之前"使用。當然也應該在其他衝突庫被使用之前,除非jQuery是最後一個匯入的。
當參數為true時,執行noConflict則會將$和jQuery對象本省的控制權全部移交給第一個產生他們的庫。
不過具體的移交機制是如何?的呢?查閱源碼即可發現,在jQuery源碼中定義了兩個私人變數_jQuery,_$。具體如下:
容易理解的是,jQuery通過上面兩個私人的變數映射了window環境下的jQuery和$兩個對象,防止了變數被強行覆蓋。一旦noConflict被調用,jquery可以通過_jQuery,_$,jQuery,$四者之間的差異,來決定控制權的移交方式,具體代碼如:
接下來看看參數設定問題,如果deep沒有設定,_$覆蓋了window.$,此時jQuery的別名$失效了,但是jQuery變數未失效,仍可使用。此時如果有其他庫或代碼重新定義了$變數的話,其控制權就轉交出去了。反之deep設定為true時,_jQuery進一步覆蓋window.jQuery,此時$和jQuery都將失效。
這種操作的好處是,不管是架構混用還是jQuery多版本共存這種高度衝突的執行環境,由於noConflict的控制權移交機制,以及本身返回違背覆蓋的私人變數jQuery對象,完全能夠通過變數映射的方式解決衝突。
樣本
瞭解了jQuery內部解決衝突的實現方式,接下來看看一些實際的情況吧。
1、將$引用的對象映射回原始的對象。
jQuery.noConflict();// 使用 jQueryjQuery("div p").hide();// 使用其他庫的 $()$("content").style.display = 'none';
2、恢複使用別名$,然後建立並執行一個函數,在這個函數的範圍中仍然將$作為jQuery的別名來使用。在這個函數中,原來的$對象是無效的。這個函數對於大多數不依賴於其他庫的外掛程式都十分有效。
jQuery.noConflict();(function($) { $(function() { // 使用 $ 作為 jQuery 別名的代碼 });})(jQuery);// 其他用 $ 作為別名的庫的代碼
3、建立一個新的別名用來在接下來的庫中使用jQuery對象。
var j = jQuery.noConflict();// 基於 jQuery 的代碼j("div p").hide();// 基於其他庫的 $() 代碼$("content").style.display = 'none';
基於這種方式,所有的jQuery代碼都通過j進行調用,避免了衝突的可能。
4、完全將jQuery移到一個新的命名空間。
var dom = {};dom.query = jQuery.noConflict(true); 結果:// 新 jQuery 的代碼dom.query("div p").hide();// 另一個庫 $() 的代碼$("content").style.display = 'none';// 另一個版本 jQuery 的代碼jQuery("div > p").hide();
解決衝突方式
衝突的方式無非3中情況:
1、其他庫先於jQuery引用($被佔用).
最簡單的我們可以在任何地方調用jQuery.noConflict函數,之後使用jQuery()座位jQuery對象的製造工廠。
jQuery.noConflict(); //將變數$的控制權移交給先匯入的庫 jQuery(function(){ jQuery("p").click(function(){ //使用jQuery變數 }); }); $("pp").style.display='none'; //其他庫的調用
此外,如果你想確保jQuery不會與其他庫衝突,但又想使用一個類似"$"的捷徑,可以使用如下代碼:
var $mj=jQuery.noConflict(); //自訂快捷變數 $mj(function(){ $mj("p").click(function(){ //使用jQuery變數 }); }); $("pp").style.display='none'; //其他庫的調用
如果你不想給jQuery自訂名稱,卻想使用$,有不與其他庫衝突.可以有兩種解決方式:
其一:
jQuery.noConflict(); jQuery(function($){ $("p").click(function(){ //在函數內部繼續使用$ }); }); $("pp").style.display='none'; //其他庫的調用
其二:
jQuery.noConflict(); //將變數$控制權讓渡(function($){ //定義匿名函數形參為$$(function(){ //匿名函數內部均為jQuery的$ $("p").click(function(){ }); });})(jQuery); //執行匿名函數且傳遞實參jQuery $("pp").style.display='none'; //其他庫的調用
這是較為理想的方式,因為可以改變最少的代碼來實現全面的相容性 2、其他庫後於jQuery被引用
你可以參考上述做一些衝突解決的方法,其實其根本就不衝突,你可以使用jQuery變數做一些jQuery的處理工作。同時可以使用$()方法作為其他庫的捷徑。
3、不同版本jQuery、且有其他庫
可以參考上述樣本,將jQuery完全移到另一個命名空間。
var dom = {};dom.query = jQuery.noConflict(true);// 新 jQuery 的代碼dom.query("div p").hide();// 另一個庫 $() 的代碼$("content").style.display = 'none';// 另一個版本 jQuery 的代碼jQuery("div > p").hide();
最後
jQuery解決衝突的機制是十分靈活的,有了這些衝突解決方案,就可以在項目中安心的使用jQuery了。