关于事件传播机制

事件:

JavaScript 和 HTML的交互是通过事件实现的。

事件是某个行为或触发,比如点击,鼠标移动:

  • 当用户点击鼠标时
  • 当网页已加载时
  • 当图像已经加载时
  • 当鼠标移动到元素上时
  • 当用户触发按键时

事件流

事件冒泡

点击div区域时,从下往上往父元素传播

事件捕获

点击div时先从树根Document开始捕获,再一层层传给子元素

DOM事件流

DOM2级事件规定事件流包括3个阶段,事件捕获阶段,处于目标阶段,时间冒泡阶段,首先发生的是事件捕获,为截取事件提供机会,然后是世纪目标接受事件,最后是冒泡阶段。
相当于先进行一次捕获阶段,再到冒泡阶段

阻止传播

阻止传播一般使用stopPropagation取消事件的进一步冒泡或者捕获 也就是取消进一步的事件捕获或冒泡,防止再触发定义在别的节点上的监听函数,但不包括再当前节点上新定义的事件监听函数。 例: 我们可以在button的事件处理程序中调用stopPropagation()从而避免注册在body上的事件发生。 若是注释掉e.stopPropagation();在点击button的时候,由于事件冒泡,body的click事件也会触发,但是调用后这句后,事件会停止传播。 undefined ##### 取消默认行为 preventDefault方法取消浏览器对当前事件的默认行为,
比如点击链接后,浏览器跳转到指定页面,或者按一下空格键,页面向下滚动一段距离。
该方法生效的前提是,事件的cancleable属性为true, 如果为false,则该方法没有效果。
该方法不会阻止事件的进一步传播,只是该事件的默认方法不会执行。

例:
可以为文本框设置校验条件。如果用户的输入不符合条件,就无法将字符输入文本框。
keypress监听函数,只能输入小写字母,否则输入事件的默认事件(写入文本框)将本取消。

1
2
3
4
5
function checkName(e){
if(e.charCode < 97 || e.charCode > 122){
e.preventDafault();
}
}
事件代理

事件代理就是利用事件冒泡,只指定一个事件处理程序,就可以管理某一类型的所有事件。(delegation)。
我们知道当一个元素上的事件被触发时,比如说点击了一个按钮,同样的事件将会在那个元素的所有祖先元素中被触发。(事件冒泡)
因此我们可以给父元素田间事件监听器,子元素添加事件,事件触发冒泡上来,可以把多个子元素的事件进行统一处理。
这叫做事件的代理。

例:
上面代码的click事件的监听函数定义在ul节点,但是实际上,它处理的是子节点li的click事件。这样的好处是,只要定义一个监听函数,就能处理多个子节点的事件,且以后再添加子节点,监听函数依然有效。

1
2
3
4
5
6
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event){
if(event.target.tagName.toLowerCase() === 'li'){
//...
}
})
事件传播过程的DEMO,演示阻止传播的效果

演示地址

HTML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<!DOCTYPE html>
<html>
<head>
<meta charset = "utf-8">
<title>Homework</title>
</head>
<body>
<button id="btn">click</button>
<div class="container">
container
<div class="box">
box
<div class="target">
target
</div>
</div>
</div>
</body>
</html>

CSS

1
2
3
4
5
6
7
.container,
.box,
.target
{
border: 2px solid pink;
padding: 10px;
}

JS

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
var btn = document.querySelector('#btn');

btn.onclick = function (e){
console.log(e);
};

btn.addEventListener('click',
function(e){
console.log(this);
});

// EVENT CAPTURING
document.querySelector('.container').addEventListener('click', function(e){
console.log('container click.. in 捕获阶段');
}, true);

document.querySelector('.box').addEventListener('click', function(e){
console.log('box click.. in 捕获阶段');
}, true);

document.querySelector('.target').addEventListener('click', function(e){
console.log('target click.. in 捕获阶段');
}, true);


// DUBBED BUBBLING
document.querySelector('.container').addEventListener('click', function(e){
console.log('container click.. in 冒泡阶段');
});

document.querySelector('.box').addEventListener('click', function(e){
// STOP EVENT HERE
e.stopPropagation();
console.log('box click.. in 冒泡阶段');
});

document.querySelector('.target').addEventListener('click', function(e){
console.log('target click.. in 冒泡阶段');
});