jQuery 與其他函式庫共存

許多 JavaScript 函式庫都使用 $ 作為主要的函式名稱,這可能會與 jQuery 產生衝突。本篇介紹如何讓 jQuery 與其他函式庫和平共存。

為什麼會衝突?

jQuery 預設使用兩個全域變數:jQuery$。當頁面載入其他也使用 $ 的函式庫時,後載入的會覆蓋先載入的:

<!-- 載入 jQuery -->
<script src="jquery.js"></script>
<!-- $ 現在是 jQuery -->

<!-- 載入其他函式庫 -->
<script src="other-library.js"></script>
<!-- $ 可能被覆蓋了 -->

常見也使用 $ 的函式庫:

  • Prototype
  • MooTools
  • YUI
  • Zepto

$.noConflict() 基本用法

$.noConflict() 讓 jQuery 釋放 $ 變數的控制權:

// 釋放 $ 變數
$.noConflict();

// $ 不再是 jQuery
// 但 jQuery 仍然可用
jQuery('div').hide();

自訂別名

可以將 jQuery 指派給自訂的變數:

var $j = $.noConflict();

// 使用 $j 代替 $
$j('div').hide();
$j('#btn').on('click', function() {
  // ...
});

完全釋放

傳入 true 可以同時釋放 jQuery$

var myQuery = $.noConflict(true);

// jQuery 和 $ 都被釋放
// 只能使用 myQuery
myQuery('div').hide();

這在載入多個 jQuery 版本時很有用。

常見使用模式

模式一:使用 jQuery 全名

最簡單的方式,直接使用 jQuery 而非 $

$.noConflict();

jQuery(document).ready(function() {
  jQuery('div').hide();
});

模式二:IIFE 區塊

在立即執行函式中,將 jQuery 傳入作為 $ 使用:

$.noConflict();

(function($) {
  // 在這個區塊內,$ 是 jQuery
  
  $(document).ready(function() {
    $('div').hide();
    $('#btn').on('click', function() {
      $(this).toggleClass('active');
    });
  });
  
})(jQuery);

// 區塊外,$ 是其他函式庫

這是最常用的模式,推薦使用。

模式三:document ready 回呼

$(document).ready() 的回呼函式中使用 $

$.noConflict();

jQuery(document).ready(function($) {
  // 在這裡 $ 是 jQuery
  $('div').hide();
});

// 外面 $ 是其他函式庫

模式四:自訂別名

使用自訂的簡短別名:

var $j = $.noConflict();

$j(document).ready(function() {
  $j('div').hide();
});

與常見函式庫共存

與 Prototype 共存

Prototype 也使用 $,需要讓 jQuery 釋放:

<script src="prototype.js"></script>
<script src="jquery.js"></script>
<script>
  // 讓 jQuery 釋放 $
  $.noConflict();
  
  // Prototype 使用 $
  $('elementId').hide();
  
  // jQuery 使用 jQuery
  jQuery('#jqueryElement').hide();
</script>

或使用 IIFE:

<script src="prototype.js"></script>
<script src="jquery.js"></script>
<script>
  $.noConflict();
  
  (function($) {
    // jQuery 程式碼
    $('div').hide();
  })(jQuery);
  
  // Prototype 程式碼
  $('elementId').observe('click', handler);
</script>

先載入其他函式庫

如果其他函式庫先載入,jQuery 會自動備份原本的 $

<script src="other-library.js"></script>
<script src="jquery.js"></script>
<script>
  // jQuery 現在是 $
  // 但原本的 $ 被備份了
  
  $.noConflict();
  // $ 恢復為原本的函式庫
  
  // 使用 jQuery
  jQuery('div').hide();
</script>

多個 jQuery 版本共存

在某些情況下,可能需要同時使用多個 jQuery 版本(例如某個插件需要舊版本):

<!-- 載入 jQuery 1.x -->
<script src="jquery-1.12.4.js"></script>
<script>
  var jQuery1 = $.noConflict(true);
</script>

<!-- 載入 jQuery 3.x -->
<script src="jquery-3.7.1.js"></script>
<script>
  var jQuery3 = $.noConflict(true);
  
  // 選擇性地將某個版本設為預設的 $
  window.$ = jQuery3;
</script>

<script>
  // 使用不同版本
  jQuery1('#oldPlugin').oldPlugin();
  jQuery3('#newFeature').newFeature();
</script>
注意:使用多個 jQuery 版本會增加頁面載入時間和複雜度,應盡量避免。

AMD/CommonJS/ES6 模組

在現代模組系統中,通常不會有全域變數衝突的問題:

CommonJS (Node.js/Browserify/Webpack)

var $ = require('jquery');

// $ 只在這個模組內有效
$('div').hide();

ES6 模組

import $ from 'jquery';

// $ 只在這個模組內有效
$('div').hide();

AMD (RequireJS)

define(['jquery'], function($) {
  // $ 只在這個區塊內有效
  $('div').hide();
});

最佳實踐

1. 總是在 IIFE 中撰寫程式碼

(function($, window, document, undefined) {
  'use strict';
  
  $(function() {
    // DOM ready
    $('#app').init();
  });
  
})(jQuery, window, document);

2. 插件開發時使用 IIFE

(function($) {
  $.fn.myPlugin = function() {
    // 使用 $
  };
})(jQuery);

3. 盡早呼叫 noConflict

<script src="jquery.js"></script>
<script>$.noConflict();</script>
<script src="other-library.js"></script>
<script src="app.js"></script>

4. 避免使用多個 jQuery 版本

如果可能,更新插件以支援新版 jQuery,而非載入多個版本。

5. 文件化你的選擇

在程式碼中說明為什麼需要 noConflict:

// 因為本頁面同時使用 Prototype,需要讓 jQuery 釋放 $
var $j = $.noConflict();

偵錯衝突問題

如果懷疑有 $ 衝突,可以檢查:

// 檢查 $ 是什麼
console.log($);
console.log($.fn ? $.fn.jquery : 'Not jQuery');

// 檢查 jQuery 是否存在
console.log(typeof jQuery);
console.log(jQuery.fn.jquery);

小結

方法說明
$.noConflict()釋放 $,保留 jQuery
$.noConflict(true)釋放 $jQuery
var $j = $.noConflict()使用自訂別名
IIFE 包裹在區塊內使用 $
模組系統使用 import/require

推薦模式

// 釋放 $
$.noConflict();

// 在 IIFE 中使用 $
(function($) {
  'use strict';
  
  $(document).ready(function() {
    // 所有 jQuery 程式碼
  });
  
})(jQuery);