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);