页面不是死物:按钮等你去点,输入框等你来敲。这个“等”,就是事件。 前面每一式的演示都在用事件,这一式,我们把它说透。
- 会用
on('事件名', fn)绑定事件,认识常用事件名 - 明白回调里的
this与$(this),会用e.preventDefault()与e.stopPropagation() - 掌握事件委托,让“新添加的元素”一出生就能响应;会用
off()解绑 - 会用
one()绑定“只响一次”的事件,用trigger()/triggerHandler()主动触发
on:事件的统一入口
jQuery 里绑定事件只有一个入口:on('事件名', 处理函数)。那些“快捷方法”——
.click(fn)、.keyup(fn)——都只是 on 的马甲,写哪个都行,
本教程统一用 on。
常用事件先混个脸熟,用到时回来翻:
| 事件 | 触发时机 | 典型场景 |
|---|---|---|
click | 单击 | 按钮、菜单 |
dblclick | 双击 | 少见,快捷操作 |
mouseenter | 鼠标移入元素(不冒泡) | 悬停高亮 |
mouseleave | 鼠标移出元素 | 悬停恢复 |
keydown | 按下按键(长按会连续触发) | 快捷键 |
keyup | 松开按键 | 输入统计、即时回显 |
change | 值改变(勾选框立即、输入框失焦时) | 表单联动 |
submit | 表单提交(回车或点提交按钮) | 表单校验 |
focus | 获得焦点 | 提示、清空默认值 |
回调里的 this
事件回调执行时,this 指向“触发事件的元素本身”(原生 DOM 元素)。
用 $(this) 把它包成 jQuery 对象,就能施展全部招式。
妙处在于:绑定的时候你并不知道用户会点哪一个——this 永远指向“当事人”,
一个处理函数就能服务整个集合。下一个演示会反复用到它。
事件委托:让新元素一出生就会响应
直接绑定有一个隐藏的坑:$('li').on('click', …) 的监听器是“钉”在当时存在的那些
li 身上的。之后新加进来的 li,身上没有监听器,点了毫无反应。
解法是事件委托:把监听器钉在恒久存在的父容器上,再传一个子元素选择器。 事件从被点的元素一路冒泡到父容器,父容器按选择器过滤——是“我的辖区”才动手。 新元素天然在父容器的辖区里,所以一出生就会响应。
直接绑定:$('#jq05-list-a li').on('click', …)
- 旧招式 · 第一式
- 旧招式 · 第二式
事件委托:$('#jq05-list-b').on('click', 'li', …)
- 旧招式 · 第一式
- 旧招式 · 第二式
左边的新条目点了没反应,右边的一点就亮——这就是委托的威力。 江湖规矩:凡是会动态添加的元素,一律用事件委托。
事件对象:preventDefault
回调的第一个参数是事件对象(惯例叫 e),它携带着这次事件的详细信息,
也提供两个关键招式。e.preventDefault() 阻止浏览器的默认行为——表单不刷新、链接不跳转。
表单校验是它的头号用武之地:
按下回车或点“报名”,页面不会刷新。
按下回车或点“报名”,页面纹丝不动,只有提示在变——默认提交被 preventDefault() 拦下了。
真实项目里会在这里先校验,一切妥当后再提交。
冒泡与 stopPropagation
事件默认冒泡:内层元素触发后,会一层层向上汇报,祖先的监听器都会听到。
多数时候这是好事(委托就靠它),但有时不想让外层听到,就用 e.stopPropagation() 在半路截住。
点按钮试试。
不勾选时点按钮:内层先说“内层听到了”,外层随后补充“外层也听到了”; 勾选后,事件走到内层为止。冒泡是委托的基石,也是“误伤”的来源——哪层要哪层不要,你说了算。
off:解绑
有绑就要有解。off() 与 on() 的写法一一对应:
常见用法是“只许点一次”——处理函数里先 off 再干活。
只响一次与主动出击:one / trigger
“只许点一次”有更省事的写法:one('事件名', fn)——它是 on 的孪生兄弟,
区别只在响应过一次就自动解绑。领券、签到、首次提示,都适合用它。
反过来,能不能用代码“替用户点一下”?可以。两个方法一对难兄难弟:
| 写法 | 行为 |
|---|---|
$el.trigger('focus') | 模拟真实事件:冒泡、触发默认行为(如让输入框获得焦点),返回 jQuery 对象 |
$el.triggerHandler('focus') | 只把绑定的处理函数跑一遍:不冒泡、不触发默认行为,返回处理函数的返回值 |
入场券: 还没领过。
点两个按钮,观察输入框与这行字的区别。
- 在例 1 右侧列表下方加一个“解绑”按钮:点击后用
off解除委托,再点“两边各添一招”验证新条目不再响应。 - 给一个输入框同时绑定
keyup与focus:获得焦点时提示“可以输入了”,松开按键时显示“已输入 N 字”。 - 思考题:事件委托为什么能让“新添加的元素”自动响应?它和直接绑定在“监听器放在哪”上有什么区别?
参考答案 1
解绑委托必须带上与绑定时相同的选择器——绑定是 on('click', 'li', …),
解绑就是 off('click', 'li')。之后旧条目与新条目都归于平静。
参考答案 2
同一个元素可以绑定多个事件,互不干扰;$(this) 让处理函数不必知道输入框的名字。
参考答案 3
直接绑定把监听器逐个挂在 li 身上——新元素出生时没人给它挂监听器,自然没反应;
委托只挂一个监听器在恒存在的父容器上,靠事件冒泡接收所有后代的事件,
再用选择器过滤——新元素天然在父容器辖区里,所以自动响应。
代价是每个后代事件都要过一遍过滤,元素极多且事件极高频时不如直接绑定精准,但常规场景毫无感觉。
本式小结
on()是事件统一入口,快捷方法都是它的马甲;- 回调里的
this是当事人,$(this)让它进入 jQuery 招式体系; preventDefault()拦默认行为,stopPropagation()截冒泡;- 动态元素靠事件委托,
off()让绑定有始有终; one()是“只响一次”的on();trigger()连默认行为一起触发,triggerHandler()只跑处理函数。
下一式,修炼显隐与动画——hide、fadeIn、slideUp 轮番登场,页面开始有了呼吸。