jQuery复习3:jQuery中的事件传播机制和事件委托

Posted by mieruko on 2016-12-16

前言:

前面几篇都在复习用法,这一篇要回忆一下机制。
大概的一个轮廓是,事件传播机制(事件冒泡,事件捕获,事件对象)和事件委托(事件绑定)。

事件的旅程————事件传播机制

首先再熟悉一遍原生js中的事件传播机制。

这里有一个html结构:

1
2
3
4
5
<div class="foo">
<span class="bar">
<a href="http://www.example.com">这是一个测试</a>
</span>
</div>

事件捕获

如果我给a元素绑定了一个click事件,然后我去点击a,此时我的浏览器如果采取的事件传播机制是事件捕获,那么我的事件是从外到里面进来的,就是说如果三个元素上都有事件侦听程序,那么第一个响应的元素是div,第二个响应的元素是bar,最后一个响应事件的才是a元素上的事件监听程序。

这种事件首先交给最外层元素,接着再交给更具体的元素的事件传播过程叫做事件捕获。

事件冒泡

还是这段程序,还是为每个元素都安装事件舰艇程序,我还是去点击a,如果此时我的浏览器采取的是事件冒泡机制,那么事件传播的顺序是a->span->foo。
反过来了!
这种当事件发生时,首先发送给最具体的元素,在这个元素获得响应机会之后,事件向上冒泡到更一般的元素的事件传播机制叫做事件冒泡。

实际应用中的情况

毫不奇怪,不同的浏览器开发者最初采用的是不同的事件传播模型,因此,最终出台的DOM标准规定应该同时使用这两种策略。
首先,事件从一般元素到具体元素逐层捕获。然后事件再通过冒泡返回DOM树的顶层。
而事件处理程序也可以注册到这个过程中的任何一个阶段。

jQuery中的事件传播模型

为了确保跨浏览器的一致性,也为了更让人容易理解。
jQuery始终会在模型的冒泡阶段注册事件处理程序

jQuery中的事件对象

我们可以通过在处理函数中添加一个参数的形式引用事件对象:

1
2
3
4
5
$(document).ready(function(){
$("#switcher").click(function(event){
console.log(event);
});
});

楼上这段程序,传入的event承接了事件对象,这个event名字不唯一,叫什么都行,只要它是事件处理程序中的第一个参数。

利用event对象,我们可以得到事件目标(event.target),还可以利用它来阻止事件冒泡(event.stopPropagation)。

阻止默认操作

有时候浏览器会给我们一些很不讨人喜欢的默认操作。
比如我点一下提交按钮,我想给它自定义一个响应,不让它跳转,而让它按我说的做。然后我为它安装事件处理程序,然后我会发现安装后它仍然会直接跳转,这时候怎么办。
这个跳转,就是浏览器的一个默认操作,我需要阻止它:

1
event.preventDefault()

tip: 既想阻止冒泡,又想阻止默认行为,这时候在事件处理函数里面返回一个false就可以了。

jQuery中的事件委托机制

这个比较重要。因为涉及到一个非常重要的方法on。

事件委托是利用事件冒泡的一项高级技术。通过事件委托,可以借助一个元素上的事件处理程序完成很多工作。

想象一个巨大的表格,它里面有一堆小格子,我希望每个小格子被点击时都有事件处理程序来响应它,那我难不成要给成千上万个小格子都安装事件处理程序???
不不不,累死了,毁性能毁内存。

为了解决这个问题,可以只在DOM的一个祖先元素上指定一个单击处理程序,借助事件冒泡,拦截子元素的事件,然后再作出响应。

on()方法

on()方法的常见调用形式:

1
element.on(事件名, 事件处理程序);

利用这种形式,我们可以给一个元素安装指定的事件的事件监听程序。

on()方法的事件委托实现:

1
element.on(事件名, 子元素, 事件处理程序);

楼上,多出的这个参数,就是事件的委托方,而element是事件的被委托方。
(子元素的传入形式是一个选择符表达式)。

如果on()方法传入的第二个参数是一个选择符表达式,jQuery会把对应的事件处理程序绑定到element对象,同时比较event.target和选择符表达式,如果匹配,jQuery会把this关键字映射到匹配的元素,否则不会执行事件处理程序

off()方法移除事件处理程序

off()方法的用法也比较简单,它是和on()方法呼应的,我们直接看一段demo思路就会比较清晰:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function btnClick1(){
alert( this.value + "-1" );
}

function btnClick2(){
alert( this.value + "-2" );
}

var $body = $("body");

// 为所有button元素的click事件绑定事件处理函数btnClick1
$body.on("click", ":button", btnClick1 );

// 为所有button元素的click事件绑定事件处理函数btnClick2
$body.on("click", ":button", btnClick2 );

//为所有a元素绑定click、mouseover、mouseleave事件
$body.on("click mouseover mouseleave", "a", function(event){
if( event.type == "click" ){
alert("点击事件");
}else if( event.type == "mouseover" ){
$(this).css("color", "red");
}else{
$(this).css("color", "blue");
}
});


// 移除body元素为所有button元素的click事件绑定的事件处理函数btnClick2
// 点击按钮,btnClick1照样执行
$body.off("click", ":button", btnClick2);


// 移除body元素为所有button元素的click事件绑定的所有事件处理函数(btnClick1和btnClick2)
// 点击按钮,不会执行任何事件处理函数
// $body.off("click", ":button");


// 注意: $body.off("click", "#btn1"); 无法移除btn1的点击事件,off()函数指定的选择器必须与on()函数传入的选择器一致。


// 移除body元素为所有元素(包括button和<a>元素)的click事件绑定的所有处理函数
// 点击按钮或链接,都不会触发执行任何事件处理函数
// $("body").off("click");


// 移除body元素为所有元素的任何事件绑定的所有处理函数
// 点击按钮,或点击链接或者鼠标移入/移出链接,都不会触发执行任何事件处理函数
// $("body").off( );

结语

jQuery具有良好的跨浏览器运行能力,对于事件传播机制的处理方式验证了这一点。
在jQuery中,不仅有on()方法,还有一个功能类似的delegate()和undelegate()方法。
虽然最重要的也最多用的仍然是on()和off()方法,不过另外两个方法也很有说头,我会另写博客做说明。