因为JavaScript在浏览器中以单线程模式运行,页面加载后,一旦页面上所有的JavaScript代码被执行完后,就只能依赖触发事件来执行JavaScript代码。
浏览器在接收到用户的鼠标或键盘输入后,会自动在对应的DOM节点上触发相应的事件。如果该节点已经绑定了对应的JavaScript处理函数,该函数就会自动调用。
由于不同的浏览器绑定事件的代码都不太一样,所以用jQuery来写代码,就屏蔽了不同浏览器的差异,我们总是编写相同的代码。
举个例子,假设要在用户点击了超链接时弹出提示框,我们用jQuery这样绑定一个click事件:
/* HTML:** <a id="test-link" href="#0">点我试试</a>**/// 获取超链接的jQuery对象:let a = $('#test-link');a.on('click', function () {alert('Hello!');});
实测:点我试试
on方法用来绑定一个事件,我们需要传入事件名称和对应的处理函数。
另一种更简化的写法是直接调用click()方法:
a.click(function () {alert('Hello!');});
两者完全等价。我们通常用后面的写法。
jQuery能够绑定的事件主要包括:
鼠标事件
- click: 鼠标单击时触发;
- dblclick:鼠标双击时触发;
- mouseenter:鼠标进入时触发;
- mouseleave:鼠标移出时触发;
- mousemove:鼠标在DOM内部移动时触发;
- hover:鼠标进入和退出时触发两个函数,相当于mouseenter加上mouseleave。
键盘事件
键盘事件仅作用在当前焦点的DOM上,通常是和。
- keydown:键盘按下时触发;
- keyup:键盘松开时触发;
- keypress:按一次键后触发。
其他事件
- focus:当DOM获得焦点时触发;
- blur:当DOM失去焦点时触发;
- change:当
、或的内容改变时触发; - submit:当
提交时触发; - ready:当页面被载入并且DOM树完成初始化后触发。
其中,ready仅作用于document对象。由于ready事件在DOM完成初始化后触发,且只触发一次,所以非常适合用来写其他的初始化代码。假设我们想给一个
submit事件,下面的代码没有预期的效果:
<html><head><script>// 代码有误:$('#testForm').on('submit', function () {alert('submit!');});</script></head><body><form id="testForm">...</form></body>
因为JavaScript在此执行的时候,
$('#testForm)返回[],并没有绑定事件到任何DOM上。
所以我们自己的初始化代码必须放到document对象的ready事件中,保证DOM已完成初始化:
<html><head><script>$(document).on('ready', function () {$('#testForm).on('submit', function () {alert('submit!');});});</script></head><body><form id="testForm">...</form></body>
这样写就没有问题了。因为相关代码会在DOM树初始化后再执行。
由于ready事件使用非常普遍,所以可以这样简化:
$(document).ready(function () {// on('submit', function)也可以简化:$('#testForm).submit(function () {alert('submit!');});});
甚至还可以再简化为:
$(function () {// init...});
上面的这种写法最为常见。如果你遇到$(function () {…})的形式,牢记这是document对象的ready事件处理函数。
完全可以反复绑定事件处理函数,它们会依次执行:
$(function () {console.log('init A...');});$(function () {console.log('init B...');});$(function () {console.log('init C...');});
事件参数
有些事件,如mousemove和keypress,我们需要获取鼠标位置和按键的值,否则监听这些事件就没什么意义了。所有事件都会传入Event对象作为参数,可以从Event对象上获取到更多的信息:
$(function () {$('#testMouseMoveDiv').mousemove(function (e) {$('#testMouseMoveSpan').text('pageX = ' + e.pageX + ', pageY = ' + e.pageY);});});
取消绑定
一个已被绑定的事件可以解除绑定,通过off('click', function)实现:
function hello() {alert('hello!');}a.click(hello); // 绑定事件// 10秒钟后解除绑定:setTimeout(function () {a.off('click', hello);}, 10000);
需要特别注意的是,下面这种写法是无效的:
// 绑定事件:a.click(function () {alert('hello!');});// 解除绑定:a.off('click', function () {alert('hello!');});
这是因为两个匿名函数虽然长得一模一样,但是它们是两个不同的函数对象,off('click', function () {…})无法移除已绑定的第一个匿名函数。
为了实现移除效果,可以使用off('click')一次性移除已绑定的click事件的所有处理函数。
同理,无参数调用off()一次性移除已绑定的所有类型的事件处理函数。
事件触发条件
一个需要注意的问题是,事件的触发总是由用户操作引发的。例如,我们监控文本框的内容改动:
let input = $('#test-input');input.change(function () {console.log('changed...');});
当用户在文本框中输入时,就会触发change事件。但是,如果用JavaScript代码去改动文本框的值,将不会触发change事件:
let input = $('#test-input');input.val('change it!'); // 无法触发change事件
有些时候,我们希望用代码触发change事件,可以直接调用无参数的change()方法来触发该事件:
let input = $('#test-input');input.val('change it!');input.change(); // 触发change事件
input.change()相当于input.trigger('change'),它是trigger()方法的简写。
为什么我们希望手动触发一个事件呢?如果不这么做,很多时候,我们就得写两份一模一样的代码。
练习
对如下的Form表单:
<!-- HTML结构 --><form id="test-form" action="test"><legend>请选择想要学习的编程语言:</legend><fieldset><p><label class="selectAll"><input type="checkbox"> <span class="selectAll">全选</span><span class="deselectAll">全不选</span></label> <a href="#0" class="invertSelect">反选</a></p><p><label><input type="checkbox" name="lang" value="javascript"> JavaScript</label></p><p><label><input type="checkbox" name="lang" value="python"> Python</label></p><p><label><input type="checkbox" name="lang" value="ruby"> Ruby</label></p><p><label><input type="checkbox" name="lang" value="haskell"> Haskell</label></p><p><label><input type="checkbox" name="lang" value="scheme"> Scheme</label></p><p><button type="submit">Submit</button></p></fieldset></form>
绑定合适的事件处理函数,实现以下逻辑:
当用户勾上“全选”时,自动选中所有语言,并把“全选”变成“全不选”;
当用户去掉“全不选”时,自动不选中所有语言;
当用户点击“反选”时,自动把所有语言状态反转(选中的变为未选,未选的变为选中);
当用户把所有语言都手动勾上时,“全选”被自动勾上,并变为“全不选”;
当用户手动去掉选中至少一种语言时,“全不选”自动被去掉选中,并变为“全选”。
letform = $('#test-form'),langs = form.find('[name=lang]'),selectAll = form.find('label.selectAll :checkbox'),selectAllLabel = form.find('label.selectAll span.selectAll'),deselectAllLabel = form.find('label.selectAll span.deselectAll'),invertSelect = form.find('a.invertSelect');// 重置初始化状态:form.find('*').show().off();form.find(':checkbox').prop('checked', false).off();deselectAllLabel.hide();// 拦截form提交事件:form.off().submit(function (e) {e.preventDefault();alert(form.serialize());});// TODO:绑定事件// 测试:console.log('请测试功能是否正常。');
