事件捕获:当一个事件触发后,从window对象出发,不断经过下级节点,直到目标节点,这个过程就是事件捕获。自内而外,从根到叶,从小到大。
事件冒泡:即是事件开始时由最具体的元素接收,然后逐级向上传播到较为不具体的节点。当事件到达目标节点之后,会沿着捕获阶段的路线原路返回,同样所有经过节点会被触发。即是自内而外,从叶到根,从小到大。
说起来很复杂,其实用一个示列就很容易理解
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
div{
margin: 50px;
overflow: hidden;
}
#div1{
width:300px;
height: 300px;
background-color: #008000;
}
#div2{
width:200px;
height:200px;
background-color: #FFFF00;
}
#div3{
width:100px;
height: 100px;
background-color: #FF0000;
}
</style>
<script type="text/javascript">
window.onload = function(){
var div1 = document.getElementById("div1");
var div2 = document.getElementById("div2");
var div3 = document.getElementById("div3");
/*
*DOM2级事件定义了两个方法,用于处理指定和删除事件处理程序的操作
* addEventListener(),removeEventLister()
* 接收三个参数
* 1.要处理的事件名,2作为事件处理程序的函数,3一个布儿值,默认为false
* 如果布儿值为true,表示在捕获阶段调用事件处理程序
* 如果为默认的false,则表示在冒泡阶段调用事件处理程序
*
* */
div1.addEventListener("click",function(){
console.log("我是div1");
alert(this.id);
},false);
div2.addEventListener("click",function(){
console.log("我是div2");
alert(this.id);
},false);
div3.addEventListener("click",function(){
console.log("我是div3");
alert(this.id);
},false);
}
</script>
</head>
<body>
<div id="div1">
<div id="div2">
<div id="div3">
</div>
</div>
</div>
</body>
</html>
很简单的写了一个测试,按照冒泡规则,当我点击div3的时候,会继续向上冒泡,会显示div2,div1。
当我点击div3之后,理论上应该是div3—>div2—>div1
然后事件的捕获,只需要将false改为true,就变成了事件的捕获,这时候如果点击div3的话,按照事件捕获规则,会从根到叶,也就是说会div1–>div2–>div3,
注意:
var btn.document.getElementById("mybtn");
btn.attachEvent("onclick",function(){
alert("click");
});
btn.attachEvent("onclick",function(){
alert("hello world");
});
//为同一个按钮绑定了两个不同的事件处理程序,但是却不按照添加的先后顺序执行
//而是以相反的顺序被触发
问题又来了
能不能阻止事件冒泡呢?答案当然是可以的!
//利用这个函数就可以阻止事件冒泡了
event.stopPropagation();
//如果将这行代码加入到刚刚那个示例的函数中去,就能阻止事件的冒泡了,这个时候就不会再冒泡了
//div1,div2不会被触发
var document.getElementById("div3");
div3.addEventListener("click",function(){
//阻止事件冒泡
event.stopPropagation();
console.log("我是div3");
alert(this.id);
},false);
----------------------------------------------------------
function() {
// IE里阻止冒泡
window.event.cancelBubble = true;
// IE里获取事件源的id
var srcID = window.event.srcElement.id;
}
function(event) {
// 非IE里阻止冒泡
event.stopPropagation();
// 非IE里获取事件源的id
var ID_src = event.target.id;
}
阻止冒泡的作用:
有时候我们需要阻止冒泡,比如存在这么一个页面A–>B–>C,c是最内层元素,如果用户点击c,则跳转页面,点击b,无反应,点击a,关闭页面,这个时候就需要阻止冒泡了,我们给A加一个点击事件关闭,给C加一个单击跳转事件,这时候如果点B,会产生冒泡就会关闭页面,如果我们不想关闭页面,那么就需要给B绑定一个单击响应事件,添加上阻止冒泡函数event.stopPropagation();即可
事件委托:
事件委托又称为事件代理,其实很好理解,就是A把事情委托给B去解决,举个例子
/*假如到了中午吃饭的时间,咦嘿,可是有的室友由于忙着玩游戏或者写作业不想离开宿舍,
* 但是又不能不吃饭,于是呢就拜托一个室友去买饭(事件委托),这样一个室友可以带很多份饭回来,
* 根据你的要求来买饭,帮你付钱。这样就会省很多事,并且如果还有其他宿舍的人也不想出去了,也
* 想让带饭,这样也可以继续带饭。(给新增的节点绑定事件)
*
*/
同理,加入ul中存在很多的li,平常li很少,可以一个一个绑定事件但是假如li很多,成千上万个呢,这时候一个个绑定一个事件,那就变得非常麻烦了,即使用循环来绑定也需要很长时间,所以这个时候事件委托就展现了它的作用,只需要给ul绑定事件,li就不需要再绑定了,这样你点击任意一个ul中的li,根据事件冒泡规则,都会触发ul中的绑定事件。这样,问题就会变得简单化了
window.onload = function() {
var ul_1 = document.getElementById('ul_1');
function clickLi() {
alert('你点击了li');
}
//为ul绑定单击响应事件
ul_1.addEventListener('click', function(event) {
// event事件对象,有一个target属性,指向事件的目标
var src = event.target;
// target里面的属性是非常多的,id名、class名、节点名等等都可以取到
if(src.nodeName.toLowerCase() == 'li') {
// 我们判断如果target事件源的节点名字是li,那就执行这个函数
//toLowerCase()是因为li不区分大小写,所以需要转换为小写
clickLi();
}
});
};
//简单提一下currentTarget ,this,target
----------------------------------------------------------------
//在事件处理程序内部,对象this,始终等于currentTarget的值
//target则只包含事件的实际目标
//如果将事件处理程序指定给了目标元素,则this、currentTarget、和target包含相同的值
----------------------------------------------------------------
var btn = document.getElementById("mybtn");
btn.onclick = function(event){
alert(event.currentTarget === this); //true
alert(event.target === this); //true
//由于click事件的目标是按钮,因此这三个值是相等的。
};
-----------------------------------------------------------------
document.body.onclick = function(event){
alert(event.currentTarget === document.body); //true
alert(this === documnet.body); //true
alert(event.target === document.getElementById("mybtn")); //true
//this和currentTarget都等于document.body,因为事件处理程序是注册到这个元素上的
//target元素等于按钮,是因为它是click事件的真正目标。
//由于按钮上并没有注册事件处理程序,结果click事件就冒泡到document.body,在那里事件得到处理。
}
-----------------------------------------------------------------
上述示例我们给ul绑定了单击响应事件,所有的li都可以触发函数,但是我们发现,这样只能是一个函数,如果我们想要给不同的li绑定不同的函数那怎么做呢?
<script type="text/javscript">
window.onload = function(){
//设置li的响应函数
function clickLi_1(){
alert("你点击的为li_1")
}
function clickLi_2(){
alert("你点击的为li_2")
}
function clickLi_3(){
alert("你点击的为li_3")
}
var ul_1 = document.getElementById("ul_1");
ul_1.addEventListener("click",function(event){
//获取实际目标的id
var ID_src = event.target.id;
if(ID_src == "Li_1"){
clickLi_1();
}
else if(ID_src == "Li_2"){
clickLi_2();
}
else if(ID_src == "Li_3"){
clickLi_3();
}
},false);
};
</script>
<body>
<ul id="ul_1">
<li id="li_1">1</li>
<li id="li_2">2</li>
<li id="li_3">3</li>
</ul>
</body>
它的原理就是利用监听父元素来给子元素绑定不同的事件,从而减少了监听的次数,提高了速度,这就是所谓的事件委托。
事件委托的原理是利用事件冒泡,如果冒泡被阻止了,那么我们就不能用事件委托的方式去监听事件了!!!