链式调用是一种编程风格,允许在单个语句中连续调用多个方法。在jQuery中,大多数方法在执行后都会返回调用它的jQuery对象本身,这使得可以继续调用其他方法。
点击上面的方法查看链式调用的效果
// 每次都要重复选择元素
var $element = $('#myElement');
$element.css('color', 'red');
$element.addClass('active');
$element.show();
$element.html('Hello World');
$element.on('click', function() {
alert('Clicked!');
});
问题:重复代码,效率较低
// 所有操作在一个链式调用中完成
$('#myElement')
.css('color', 'red')
.addClass('active')
.show()
.html('Hello World')
.on('click', function() {
alert('Clicked!');
});
优点:简洁高效,易于阅读
$('#element') → 返回jQuery对象
.css('color', 'red') → 执行后返回this
.addClass('active') → 继续在同一个对象上操作
可以继续调用其他方法,直到链结束
每次调用都返回jQuery对象// 每个方法执行后都返回jQuery对象
var result1 = $('#element').css('color', 'red');
// result1 是 jQuery 对象
var result2 = result1.addClass('active');
// result2 是同一个 jQuery 对象
console.log(result1 === result2); // true
console.log($('#element') === $('#element').css('color', 'red')); // false
// 注意:两个不同的jQuery对象实例,但都指向同一个DOM元素
| 类别 | 方法示例 | 是否支持链式 | 说明 |
|---|---|---|---|
| CSS操作 | .css(), .addClass(), .removeClass(), .toggleClass() | 是 | 所有CSS操作方法都支持链式 |
| DOM操作 | .html(), .text(), .append(), .prepend(), .before(), .after() | 是 | DOM操作方法通常返回原元素 |
| 属性操作 | .attr(), .prop(), .data(), .val() | 是 | 设置操作支持链式,获取操作不支持 |
| 事件处理 | .on(), .off(), .click(), .hover(), .bind(), .unbind() | 是 | 事件绑定方法支持链式 |
| 效果动画 | .show(), .hide(), .fadeIn(), .fadeOut(), .slideUp(), .slideDown() | 是 | 动画方法支持链式,但动画是异步的 |
| 获取方法 | .text(), .html(), .val(), .attr(), .css() | 否 | 获取值时返回字符串/数值,不是jQuery对象 |
| 位置尺寸 | .offset(), .position(), .width(), .height() | 否 | 返回对象或数值,不能链式 |
| 遍历方法 | .find(), .children(), .parent(), .siblings() | 是 | 返回新的jQuery对象,可以继续链式 |
// 模式1:初始化设置
$('.widget')
.css({
'border': '1px solid #ddd',
'padding': '10px',
'margin': '5px'
})
.addClass('ui-widget')
.attr('data-widget-id', Date.now())
.on('click', function() {
$(this).toggleClass('active');
});
// 模式2:表单处理
$('#contact-form')
.find('input, textarea')
.addClass('form-control')
.css('margin-bottom', '10px')
.on('focus', function() {
$(this).css('border-color', '#3498db');
})
.on('blur', function() {
$(this).css('border-color', '#ddd');
});
// 模式3:动画序列
$('#notification')
.hide()
.html('操作成功!')
.css({
'background': '#4CAF50',
'color': 'white',
'padding': '15px',
'border-radius': '5px'
})
.fadeIn(500)
.delay(2000)
.fadeOut(500, function() {
$(this).remove();
});
// 模式4:条件链式
var $button = $('#submit-btn');
$button
.prop('disabled', true)
.text('提交中...')
.addClass('disabled');
// 根据条件添加不同类
if (isValid) {
$button.addClass('btn-success');
} else {
$button.addClass('btn-error');
}
// 继续链式
$button.removeClass('disabled');
// .end() 返回上一级jQuery对象
$('#container')
.find('.item') // 切换到.item集合
.css('color', 'red')
.addClass('active')
.end() // 返回到#container
.css('border', '1px solid blue');
// 等同于:
// var $container = $('#container');
// var $items = $container.find('.item');
// $items.css('color', 'red').addClass('active');
// $container.css('border', '1px solid blue');
// 多层嵌套示例
$('ul.first')
.find('.item')
.addClass('highlight')
.find('span')
.addClass('red')
.end() // 返回到.item
.find('a')
.addClass('blue')
.end()
.end() // 返回到ul.first
.addClass('processed');
// .addBack() 将上一级元素添加到当前集合
$('div.container')
.children('p') // 选择所有子段落
.addClass('highlight') // 给段落添加类
.addBack() // 将.container也添加到集合
.addClass('has-highlight'); // 给.container添加类
// 结果:所有p和.container都有.has-highlight类
// 复杂示例:同时操作多个层级
$('.menu')
.find('li')
.addClass('menu-item')
.find('a')
.addClass('menu-link')
.on('click', function(e) {
e.preventDefault();
$(this).toggleClass('active');
})
.end() // 回到li
.addBack() // 包含.menu和li
.css('transition', 'all 0.3s');
// 问题:动画是异步的,链式调用会立即执行
$('#element')
.slideUp(1000) // 动画1秒
.addClass('hidden') // 立即执行,不等动画完成
.slideDown(1000); // 立即执行,不等.addClass完成
// 解决方案1:使用回调函数
$('#element').slideUp(1000, function() {
$(this)
.addClass('hidden')
.slideDown(1000);
});
// 解决方案2:使用.promise()和.done()
$('#element')
.slideUp(1000)
.promise()
.done(function() {
$(this)
.addClass('hidden')
.slideDown(1000);
});
// 解决方案3:队列控制
$('#element')
.queue(function(next) {
$(this).slideUp(1000);
next();
})
.queue(function(next) {
$(this).addClass('hidden');
next();
})
.queue(function(next) {
$(this).slideDown(1000);
next();
});
// 解决方案4:使用jQuery.fx.off关闭动画(开发测试用)
$.fx.off = true; // 关闭所有动画
$('#element')
.slideUp(1000) // 立即完成
.addClass('hidden') // 立即执行
.slideDown(1000); // 立即完成
// 方法1:扩展jQuery.fn
(function($) {
$.fn.highlight = function(options) {
var settings = $.extend({
color: 'yellow',
duration: 1000
}, options);
return this.each(function() {
var $this = $(this);
var originalColor = $this.css('background-color');
$this
.css('background-color', settings.color)
.animate({
backgroundColor: originalColor
}, settings.duration);
});
// 注意:返回this可以链式调用
};
$.fn.resetStyle = function() {
return this.css({
'background-color': '',
'color': '',
'border': ''
});
};
})(jQuery);
// 使用自定义链式方法
$('#element')
.highlight({color: '#ff0'})
.addClass('highlighted')
.resetStyle()
.fadeOut();
// 方法2:创建完整的链式API
$.fn.myPlugin = function(method) {
var methods = {
init: function(options) {
return this.each(function() {
var $this = $(this);
$this.data('myPlugin', {
settings: $.extend({}, options)
});
});
},
show: function() {
return this.css('display', 'block');
},
hide: function() {
return this.css('display', 'none');
},
toggle: function() {
return this.each(function() {
var $this = $(this);
$this.toggle();
});
}
};
if (methods[method]) {
return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
} else if (typeof method === 'object' || !method) {
return methods.init.apply(this, arguments);
} else {
$.error('Method ' + method + ' does not exist on jQuery.myPlugin');
}
};
// 技巧1:使用.tap()方法调试(类似Ruby的tap)
$.fn.tap = function(callback) {
callback.call(this, this);
return this;
};
$('#element')
.css('color', 'red')
.tap(function($el) {
console.log('当前颜色:', $el.css('color'));
console.log('DOM元素:', $el[0]);
})
.addClass('active')
.fadeOut();
// 技巧2:插入调试断点
$('#element')
.css('color', 'red')
.addClass(function() {
console.log('添加类前的状态:', this.className);
return 'active';
})
.on('click', function() {
debugger; // 浏览器调试器断点
console.log('点击事件触发');
});
// 技巧3:记录链式过程
var chainLog = [];
$.fn.log = function(message) {
chainLog.push({
message: message,
element: this.selector || 'Unknown',
time: Date.now()
});
console.log(message, this);
return this;
};
$('#element')
.log('开始链式调用')
.css('color', 'red')
.log('设置颜色为红色')
.addClass('active')
.log('添加active类');
// 性能优化示例
// 不好:重复创建jQuery对象
$('#element').css('color', 'red');
$('#element').addClass('active');
$('#element').show();
$('#element').html('test');
// 好:链式调用,只创建一次jQuery对象
$('#element')
.css('color', 'red')
.addClass('active')
.show()
.html('test');
// 更好:缓存jQuery对象
var $element = $('#element');
$element
.css('color', 'red')
.addClass('active')
.show()
.html('test');
// 注意:链式调用本身不提供性能优势
// 优势在于减少重复的DOM查询和jQuery对象创建
// 特殊情况:大量元素操作
var $items = $('.items'); // 缓存选择结果
// 链式操作每个元素
$items
.css('color', 'red')
.addClass('item')
.on('click', function() {
$(this).toggleClass('active');
});
// 对于大量元素,考虑性能
var items = document.querySelectorAll('.items');
Array.prototype.forEach.call(items, function(item) {
// 直接操作DOM可能更快
item.style.color = 'red';
item.classList.add('item');
item.addEventListener('click', function() {
this.classList.toggle('active');
});
});
// 获取操作返回非jQuery对象
var text = $('#element')
.css('color', 'red') // 设置,返回jQuery对象
.text(); // 获取,返回字符串
// text是字符串,不能继续链式
// text.addClass('active'); // 错误!
// 解决方案:分离获取操作
var $element = $('#element').css('color', 'red');
var text = $element.text();
// 或者
var text = $('#element').css('color', 'red').text();
// 动画是异步的
$('#element')
.fadeOut(1000) // 开始动画(1秒)
.remove(); // 立即移除元素!
// 解决方案:使用回调
$('#element').fadeOut(1000, function() {
$(this).remove();
});
// 或者使用.promise()
$('#element')
.fadeOut(1000)
.promise()
.done(function() {
$(this).remove();
});