第 3 章 · jQuery 事件模型与事件委托
本章目标:掌握 on / off / one 与事件对象;理解 事件委托 $(parent).on('click', '.child', fn) 的原理与适用场景;处理 表单事件 与 自定义事件 trigger;结合 C 端门户 轮播 / 菜单 与 admin-demo 后台交互完成实战。
学时建议:4~5 小时(含 1.5 小时跟练)
前置:jquery-layui ch01~ch02;frontend-web ch08(事件基础)。
3.1 事件绑定:on、off、one
jQuery 1.7+ 统一用 .on() 替代 .bind()、.delegate()、.live()(已废弃)。
// 基本绑定
$('#btn-search').on('click', function (e) {
e.preventDefault(); // 若在 <form> 内或 <a> 上
console.log('搜索', $(this).text());
});
// 命名空间,便于批量解绑
$('#btn-export').on('click.export', handler);
$('#btn-export').off('click.export');
// 只触发一次
$('#welcome-modal .js-close').one('click', function () {
$(this).closest('.modal').hide();
});
// 解绑
$('#btn-search').off('click'); // 移除所有 click
$('#btn-search').off('click', handler); // 移除指定函数
| 方法 | 作用 |
|---|---|
.on(events, handler) | 绑定一个或多个事件 |
.on(events, selector, handler) | 事件委托 |
.off(events) | 解绑 |
.one(events, handler) | 单次绑定 |
3.2 事件对象
$('.sidebar__menu').on('click', 'li', function (event) {
// event 是 jQuery 包装的事件对象,兼容旧 IE
event.preventDefault();
event.stopPropagation();
var $target = $(event.currentTarget); // 当前绑定元素 li
var $origin = $(event.target); // 实际点击节点(可能是子 span)
console.log('类型', event.type);
console.log('是否委托', event.delegateTarget); // .sidebar__menu
});
| 属性 / 方法 | 说明 |
|---|---|
event.target | 触发源 DOM(可能为子元素) |
event.currentTarget | 当前处理函数所在元素 |
event.delegateTarget | 委托绑定的祖先 |
preventDefault() | 阻止默认行为(表单提交、链接跳转) |
stopPropagation() | 阻止冒泡 |
which / keyCode | 鼠标键 / 键盘码(1.12 仍可用) |
3.3 事件委托:核心模式
问题:#product-tbody 行动态增删,若对每行 .js-remove 单独 .on('click'),新行无事件。
解决:把监听绑在稳定父节点上,用选择器过滤目标。
// ✅ 推荐:委托
$('#product-tbody').on('click', '.js-remove', function () {
$(this).closest('tr').fadeOut(200, function () {
$(this).remove();
});
});
// ❌ 不推荐:直接绑定(仅对现有行有效)
$('.js-remove').on('click', fn);
事件委托流程
用户点击 .js-remove
↓ 冒泡
tbody#product-tbody 上的 click 监听器
↓ 检查 event.target 是否匹配 '.js-remove'
匹配 → 执行 handler,this 指向 .js-remove 元素
| 场景 | 是否委托 |
|---|---|
| 动态列表增删 | ✅ |
| 表格内按钮 | ✅ |
| 页面唯一静态按钮 | 可直接绑定 |
| document 全局快捷键 | $(document).on('keydown', fn) |
性能:委托减少监听器数量;避免绑在 document 上过宽选择器。
3.4 常用 DOM 事件速查
// 鼠标
$el.on('click dblclick mouseenter mouseleave', fn);
// 键盘
$('input[name="keyword"]').on('keydown', function (e) {
if (e.which === 13) { // Enter
$('#btn-search').trigger('click');
}
});
// 表单
$('form#filter-form').on('submit', function (e) {
e.preventDefault();
var data = $(this).serialize(); // ch04 详述
console.log(data);
});
$('select[name="status"]').on('change', function () {
var val = $(this).val();
filterByStatus(val);
});
// 窗口
$(window).on('resize', debounce(layoutSidebar, 150));
| 事件 | admin-demo 用途 |
|---|---|
click | 按钮、菜单、删除 |
submit | 筛选表单 |
change | 下拉状态筛选 |
keydown | 搜索框回车 |
resize | 侧栏折叠(响应式) |
3.5 自定义事件与 trigger
// 定义
$(document).on('product:updated', function (e, payload) {
console.log('商品已更新', payload.sku, payload.name);
refreshRow(payload);
});
// 触发(可传额外参数)
$(document).trigger('product:updated', [{ sku: 'SKU-001', name: '示例礼盒' }]);
// 局部触发
$('#product-panel').trigger('reload');
$('#product-panel').on('reload', loadProducts);
| API | 作用 |
|---|---|
.trigger('event') | 触发绑定在元素上的 handler |
.triggerHandler('event') | 仅执行第一个 handler,不冒泡 |
| 自定义名 | 建议 模块:动作 如 cart:added |
模块解耦:Ajax 保存成功后 trigger('product:updated'),表格与统计卡片分别监听,无需互相引用。
3.6 C 端门户:轮播与菜单事件
参考行业常见 jQuery 1.12.x 老门户页的交互模式(简化教学版)。
3.6.1 轮播指示器
<div class="banner" id="home-banner">
<ul class="banner__slides">
<li class="is-active"><img src="/static/img/banner1.jpg" alt=""></li>
<li><img src="/static/img/banner2.jpg" alt=""></li>
<li><img src="/static/img/banner3.jpg" alt=""></li>
</ul>
<ol class="banner__dots">
<li class="is-active" data-index="0"></li>
<li data-index="1"></li>
<li data-index="2"></li>
</ol>
</div>