支持IE6-8,包含了大量传统特性,API相对宽松。
放弃IE6-8支持,代码更精简,性能更好。
现代化版本,支持Promise,更严格的API,更好的性能。
特点:
最后版本:1.12.4
特点:
最后版本:2.2.4
特点:
最新版本:3.6.0+
<!-- CDN 链接 -->
<!-- jQuery 3.6.0 (最新推荐) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- jQuery 兼容版本 (支持IE6-8) -->
<script src="https://code.jquery.com/jquery-1.12.4.min.js"></script>
<!-- jQuery 2.x (不支持IE6-8) -->
<script src="https://code.jquery.com/jquery-2.2.4.min.js"></script>
<!-- 压缩版 vs 开发版 -->
<script src="jquery-3.6.0.min.js"></script> <!-- 生产环境 -->
<script src="jquery-3.6.0.js"></script> <!-- 开发环境 -->
<!-- 迁移插件 (用于平滑迁移) -->
<script src="https://code.jquery.com/jquery-migrate-3.3.2.min.js"></script>
适用于:现代浏览器应用,希望一步到位
适用于:大型遗留系统,需要逐步升级
| 阶段 | 时间 | 任务 | 产出 |
|---|---|---|---|
| 评估阶段 | 1-2天 | 代码审查、依赖分析 | 迁移计划文档 |
| 准备阶段 | 2-3天 | 搭建测试环境、备份 | 测试环境、代码备份 |
| 迁移阶段 | 3-7天 | 逐步升级、修复问题 | 可运行的新版本 |
| 测试阶段 | 3-5天 | 功能测试、性能测试 | 测试报告、性能数据 |
| 上线阶段 | 1天 | 生产环境部署、监控 | 成功上线、监控报告 |
以下是jQuery 3.x中废弃或移除的主要API及其替代方案。
替代方案:使用.on()和.off()
替代方案:使用.on('load', ...)等形式
注意:现在只对有限集合返回true
替代方案:使用.first(), .last(), .eq()等方法
// 旧的事件绑定方式
$('#button').click(function() {
console.log('clicked');
});
// 旧的绑定/解绑
$('#element').bind('click', handler);
$('#element').unbind('click', handler);
// 委托事件
$('#parent').delegate('.child', 'click', handler);
$('#parent').undelegate('.child', 'click', handler);
// 快捷方法
$(window).load(function() {
// 页面加载完成
});
$('#image').error(function() {
// 图片加载失败
});
// 新的事件绑定方式
$('#button').on('click', function() {
console.log('clicked');
});
// 新的绑定/解绑
$('#element').on('click', handler);
$('#element').off('click', handler);
// 委托事件 (推荐方式)
$('#parent').on('click', '.child', handler);
$('#parent').off('click', '.child', handler);
// 使用on方法
$(window).on('load', function() {
// 页面加载完成
});
$('#image').on('error', function() {
// 图片加载失败
});
// 废弃的选择器语法
$('li:first'); // 废弃
$('li:last'); // 废弃
$('li:eq(2)'); // 废弃
$('li:lt(3)'); // 废弃
$('li:gt(1)'); // 废弃
$('li:even'); // 废弃
$('li:odd'); // 废弃
// 废弃的属性选择器
$('[class!="hidden"]'); // 废弃
// toggle() 方法
$('#element').toggle(handler1, handler2);
// 使用jQuery方法替代
$('li').first(); // 推荐
$('li').last(); // 推荐
$('li').eq(2); // 推荐
$('li').slice(0, 3);// lt(3)的替代
$('li').slice(2); // gt(1)的替代
$('li').filter(':even'); // 替代方案
$('li').filter(':odd'); // 替代方案
// 使用:not()选择器
$('li:not(.hidden)');
// 手动实现toggle功能
var toggle = true;
$('#element').click(function() {
if (toggle) {
handler1();
} else {
handler2();
}
toggle = !toggle;
});
// 或者使用事件命名空间
$('#element')
.on('click.toggle1', handler1)
.on('click.toggle2', handler2);
// 废弃的全局AJAX事件方法
$.ajaxStart(function() {});
$.ajaxStop(function() {});
$.ajaxComplete(function() {});
$.ajaxError(function() {});
$.ajaxSuccess(function() {});
// 同步AJAX (不推荐)
$.ajax({
url: 'test.html',
async: false // 同步请求
});
// 旧的AJAX快捷方法参数
$.get(url, data, success, 'jsonp');
// 使用事件监听方式
$(document)
.on('ajaxStart', function() {})
.on('ajaxStop', function() {})
.on('ajaxComplete', function() {})
.on('ajaxError', function() {})
.on('ajaxSuccess', function() {});
// 始终使用异步AJAX
$.ajax({
url: 'test.html',
async: true // 异步请求
}).then(function(data) {
// 处理数据
});
// 使用显式的dataType参数
$.ajax({
url: url,
data: data,
dataType: 'jsonp',
success: success
});
// 或者使用Promise方式
$.get(url, data)
.done(success)
.fail(error);
| 废弃API | 替代方案 | 版本 | 严重性 |
|---|---|---|---|
.bind()/.unbind() |
.on()/.off() |
1.7 | 高 |
.delegate()/.undelegate() |
.on()/.off() |
1.7 | 高 |
.load()/.unload()/.error() |
.on('load', ...) |
1.8 | 中 |
.toggle(fn, fn) |
手动实现或使用事件命名空间 | 1.9 | 中 |
.size() |
.length属性 |
1.8 | 中 |
.andSelf() |
.addBack() |
1.8 | 中 |
jQuery.browser |
特性检测(Modernizr等) | 1.9 | 高 |
jQuery.sub() |
无直接替代 | 1.9 | 低 |
以下变更可能破坏现有代码,需要特别注意。
这些变更可能导致现有代码行为改变或完全失效。
// 1. 隐藏元素的尺寸
// 旧版本可能返回0或错误值
var width = $('.hidden-element').width();
// 2. :hidden 选择器
// 包含 visibility: hidden 的元素
$(':hidden').show();
// 3. 属性值包含选择器
$('[name="test[]"]') // 可能匹配不正确
// 4. 文档顺序
// .get() 返回原生数组,不是jQuery对象
// 1. 隐藏元素的尺寸
// 现在会尝试计算,可能返回实际值
var width = $('.hidden-element').width();
// 2. :hidden 选择器
// 不再匹配 visibility: hidden 的元素
$(':hidden').show(); // 只显示 display: none 的元素
// 3. 属性值包含选择器
$('[name="test[]"]') // 现在正确匹配
// 4. 文档顺序
// .get() 返回数组,但保持jQuery的文档顺序
// jQuery 1.x/2.x
$('#element')
.slideUp()
.delay(1000)
.slideDown();
// 动画会按顺序执行
// jQuery 3.x
$('#element')
.slideUp()
.delay(1000)
.slideDown();
// 行为基本一致,但内部实现更高效
// 主要变更:.promise() 现在返回原生Promise
$('#element').fadeIn().promise()
.then(function() {
// 动画完成
});
// 现在是真正的Promise/A+兼容
// 数据属性名转换
// jQuery 1.x/2.x 转换规则:
// data-max-value → maxValue (驼峰)
// data-max_value → max_value (保持)
// jQuery 3.x 转换规则:
// data-max-value → maxValue (驼峰)
// data-max_value → maxValue (驼峰,下划线被视为连字符)
// 建议:始终使用一致的数据属性命名
<div data-max-value="100"></div>
// 或者
<div data_max_value="100"></div>
// 在JavaScript中统一使用驼峰
$('div').data('maxValue'); // 推荐
在jQuery 3.x中,一些事件对象属性已被标准化:
event.which 现在与 event.keyCode 和 event.charCode 保持一致event.pageX/pageY 在缩放页面时计算更精确event.isDefaultPrevented() 现在更可靠
// jQuery 1.x/2.x
// 通过 .html() 插入的脚本可能不会立即执行
// jQuery 3.x
// 通过 .html() 插入的脚本会立即执行(同步)
$('#container').html('<script>console.log("立即执行")</script>');
// 如果需要控制执行时机,使用以下方法:
// 方法1:使用DOM API
var script = document.createElement('script');
script.textContent = 'console.log("控制执行")';
$('#container').append(script);
// 方法2:使用jQuery的全局方法
$.globalEval('console.log("全局执行")');
// 方法3:使用回调
$('#container').html('<script>console.log("脚本")</script>', function() {
console.log('内容已插入');
});
.width()、.height()、.innerWidth()、.outerWidth()等方法的计算更加精确,特别是在处理边框、内边距和盒模型时。
// 盒模型处理
var element = $('#myElement');
// jQuery 1.x/2.x
// .width() 返回 content width,忽略 box-sizing
// jQuery 3.x
// .width() 返回 content width,考虑 box-sizing
// 建议:明确指定需要获取的宽度类型
var contentWidth = element.width(); // content width
var innerWidth = element.innerWidth(); // content + padding
var outerWidth = element.outerWidth(); // content + padding + border
var outerWidthMargin = element.outerWidth(true); // content + padding + border + margin
// 对于隐藏元素
if (element.is(':visible')) {
var width = element.width();
} else {
// 临时显示计算
element.show();
var width = element.width();
element.hide();
}
jQuery迁移插件可以帮助识别和修复废弃API的使用,是升级过程中最重要的工具。
<!-- 引入顺序很重要 -->
<script src="jquery-3.6.0.js"></script>
<script src="jquery-migrate-3.3.2.js"></script>
<!-- 压缩版 -->
<script src="jquery-3.6.0.min.js"></script>
<script src="jquery-migrate-3.3.2.min.js"></script>
// 1. 基本配置
jQuery.migrateMute = false; // 显示所有警告
jQuery.migrateTrace = false; // 显示堆栈跟踪
jQuery.migrateWarnings = []; // 存储所有警告
// 2. 静默特定警告
jQuery.migrateWarnings = [];
var originalWarn = console.warn;
console.warn = function(msg) {
if (msg.indexOf('JQMIGRATE') !== -1) {
jQuery.migrateWarnings.push(msg);
// 可以在这里过滤特定警告
if (msg.indexOf('toggle(fn, fn)') === -1) {
originalWarn.apply(console, arguments);
}
} else {
originalWarn.apply(console, arguments);
}
};
// 3. 获取所有警告
console.log('发现警告:', jQuery.migrateWarnings.length);
jQuery.migrateWarnings.forEach(function(warning, index) {
console.log(index + ': ' + warning);
});
// 4. 在生产环境禁用迁移插件
if (window.location.hostname !== 'localhost') {
// 不加载迁移插件
// 或者设置静默模式
jQuery.migrateMute = true;
}
静态代码分析,检测废弃API使用。
{
"plugins": ["jquery"],
"rules": {
"jquery/no-bind": "error",
"jquery/no-delegate": "error",
"jquery/no-load": "error"
}
}
创建自己的检查工具,针对项目特定需求。
// 检查废弃API使用
function checkDeprecatedAPIs() {
var patterns = [
/\.bind\(/,
/\.delegate\(/,
/\.load\(function/,
/jQuery\.browser/
];
// 扫描代码...
}
测试单个jQuery功能点:
// 使用QUnit或Jest
QUnit.test('事件处理', function(assert) {
var done = assert.async();
var $button = $('#test-button');
var clicked = false;
$button.on('click', function() {
clicked = true;
assert.ok(clicked, '点击事件触发');
done();
});
$button.trigger('click');
});
// 测试动画
QUnit.test('淡入动画', function(assert) {
var done = assert.async();
var $div = $('#test-div').hide();
$div.fadeIn(500).promise().then(function() {
assert.equal($div.css('opacity'), '1', '元素已淡入');
done();
});
});
测试多个组件的交互:
// 测试AJAX交互
QUnit.test('数据加载和渲染', function(assert) {
var done = assert.async();
// 模拟AJAX响应
$.mockjax({
url: '/api/data',
responseText: [{ id: 1, name: 'Test' }]
});
$.getJSON('/api/data').then(function(data) {
// 渲染数据
var html = data.map(function(item) {
return '<li>' + item.name + '</li>';
}).join('');
$('#list').html(html);
// 验证
assert.equal($('#list li').length, 1, '正确渲染数据');
assert.equal($('#list li').text(), 'Test', '内容正确');
done();
});
});
// 性能测试工具
function performanceTest() {
var iterations = 1000;
var start, end;
// 测试选择器性能
start = performance.now();
for (var i = 0; i < iterations; i++) {
$('.test-item').hide();
$('.test-item').show();
}
end = performance.now();
console.log('选择器性能:', end - start, 'ms');
// 测试DOM操作性能
start = performance.now();
for (var i = 0; i < iterations; i++) {
$('#container').append('<div>Test</div>');
$('#container').empty();
}
end = performance.now();
console.log('DOM操作性能:', end - start, 'ms');
// 测试事件处理性能
start = performance.now();
for (var i = 0; i < iterations; i++) {
$('body').on('click.test', '.test-btn', function() {});
$('body').off('click.test', '.test-btn');
}
end = performance.now();
console.log('事件处理性能:', end - start, 'ms');
}
// 内存泄漏测试
function memoryLeakTest() {
var leaks = [];
// 创建可能的内存泄漏
for (var i = 0; i < 1000; i++) {
leaks.push($('<div></div>').data('bigData', new Array(10000)));
}
// 强制垃圾回收(仅限开发工具)
if (window.gc) {
window.gc();
}
console.log('内存使用情况:', window.performance.memory);
}
| 浏览器 | jQuery 1.12.4 | jQuery 2.2.4 | jQuery 3.6.0 | 测试要点 |
|---|---|---|---|---|
| Chrome (最新) | ES6特性、Promise | |||
| Firefox (最新) | CSS动画、Web API | |||
| Safari (最新) | 触摸事件、弹性滚动 | |||
| Edge (最新) | Web组件、模块 | |||
| IE 11 | 传统API、ActiveX | |||
| IE 9-10 | CSS3选择器、ES5 | |||
| IE 6-8 | 基本DOM操作 |
// 性能监控
$(document).ready(function() {
// 记录jQuery版本
console.log('jQuery版本:', $.fn.jquery);
// 监控AJAX请求
$(document).ajaxSend(function(event, jqxhr, settings) {
console.time('ajax-' + settings.url);
});
$(document).ajaxComplete(function(event, jqxhr, settings) {
console.timeEnd('ajax-' + settings.url);
});
// 监控事件处理性能
var eventCount = 0;
var slowEvents = [];
$(document).on('click mouseenter mouseleave', function(e) {
var start = performance.now();
// 原有事件处理逻辑
var duration = performance.now() - start;
if (duration > 16) { // 超过一帧时间
slowEvents.push({
type: e.type,
target: e.target.tagName,
duration: duration
});
}
});
// 定期报告
setInterval(function() {
if (slowEvents.length > 0) {
console.warn('慢事件处理:', slowEvents);
slowEvents = [];
}
}, 10000);
});