My Little World

事件冒泡和事件捕获

addEventListener/attachEvent/element.onclick

辨别区分addEventListener、attachEvent和element.onclick

attachEvent事件

attachEvent是ie添加事件处理程序,接收两个参数,其中事件类型名称要加”on”,
可以添加多个事件处理程序,按照添加顺序相反的顺序触发

addEventListener事件

addEventListener是给非ie添加事件处理程序,接收三个参数,第一个是事件名,不需要加“on”,
第二个是绑定的函数,第三个参数是一个布尔值,如果是false,就使用传统的冒泡方式,
如果为true,就在捕获阶段调用事件处理程序
可以添加多个事件处理程序,按照添加顺序触发

onclick

el.onclick相当于在标签上写onclick

区别

1.上下文
attachEvent会在全局作用域中运行,this等于window对象
addEventLinstener在其依附的元素的作用域中运行,this等于绑定元素对象
使this关键字都指向元素处理方法

1
2
3
4
5
6
function bind(el, fn, type){
var _fn = function(){
fn.apply(el, arguments);
};
window.addEventListener ? el.addEventListener(type, _fn, false) : el.attachEvent("on" + type, _fn);
}

2.绑定
el.onclick通过标签的onclick属性输入到文档,然后由文档解析成事件
attachEvent和addEventLinstener要在文档解析完成以后,通过文档的dom接口去绑定的事件
资源加载和页面事件

3.取消绑定
el.onclick:el.onclick=null;
addEventListener:removeEventListener();
attachEvent():detachEvent()

4.获取event事件
非IE:

1
2
3
4
5
6
el.onclick=function(event){
  alert(event.type); //"click"
};
el.addEventListener("click",function(event){
  alert(event.type); //"click"
},false);

IE:
通过el.onclick绑定的事件处理程序中,event对象作为window对象的一个属性存在。
el.onclick=function(){
  var event=window.event;
  alert(event.type); //“click”
}
如果通过attachEvent()添加事件处理程序时,event对象作为参数被传入事件处理程序,
el.attachEvent(“onclick”,function(event){
  alert(event.type); //“click”
});

标签时一样

1
<input type="button" value="Click me" onclick="alert(event.type)"/>   //"click"

事件捕获、事件冒泡

二者是指当事件在某一DOM元素被触发时,该DOM元素的父级元素也绑定了触发事件,则触发事件的执行顺序

事件冒泡

事件自下而上依次执行,先执行子元素触发事件,再执行父元素触发事件,
addEventListener第三个参数设置为false,参数不设置默认是冒泡执行

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
<body>
<div id="parent">
  <div id="child" class="child">您好</div>
</div>
</body>

<script type="text/javascript">
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+this.id);
})
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+this.id)
})
document.getElementById("parent").onclick=function(e){
alert("parentonclik事件被触发,"+this.id);
}
document.getElementById("child").onclick=function(e){
alert("childonclik事件被触发,"+this.id);
}
</script>
//点击'您好',弹出顺序:child事件被触发->childonclik事件被触发->parent事件被触发->parentonclik事件被触发
<script type="text/javascript">
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+this.id);
},false)
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+this.id)
},true)
</script>
//点击'您好',先弹出child事件被触发,再弹出parent事件被触发

事件捕获

事件从上到下一次执行,先执行父元素触发事件,再执行子元素触发事件,
addEventListener第三个参数设置为true

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
<body>
<div id="parent">
  <div id="child" class="child">您好</div>
</div>
</body>

<script type="text/javascript">
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+this.id);
},true)
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+this.id)
},true)
document.getElementById("parent").onclick=function(e){
alert("parentonclik事件被触发,"+this.id);
}
document.getElementById("child").onclick=function(e){
alert("childonclik事件被触发,"+this.id);
}
</script>
//点击'您好',弹出顺序:parent事件被触发->child事件被触发->childonclik事件被触发->parentonclik事件被触发
<script type="text/javascript">
document.getElementById("parent").addEventListener("click",function(e){
alert("parent事件被触发,"+this.id);
},true)
document.getElementById("child").addEventListener("click",function(e){
alert("child事件被触发,"+this.id)
},false)
</script>

//点击'您好',先弹出parent事件被触发,再弹出child事件被触发

应用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//要求:鼠标放到li上对应的li背景变灰
<ul>
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
<li>item6</li>
</ul>
//实现一:利用事件冒泡实现,不用遍历所有li节点
$("ul").on("mouseover",function(e){
$(e.target).css("background-color","#ddd").siblings().css("background-color","white");
})
//实现二:给每个li绑定事件,缺点,动态的加载了一些元素,新增li后,还要再绑定一次事件
$("li").on("mouseover",function(){
$(this).css("background-color","#ddd").siblings().css("background-color","white");
})

禁止冒泡

1
2
3
4
5
6
7
8
9
function doSomething(e) {
if (!e) {//微软模型
var e = window.event;
e.cancelBubble = true;
}
if (e.stopPropagation) {//w3c事件模型
e.stopPropagation();
}
}

补充

事件委托是什么?有什么好处?

假设父元素有4个儿子,我不监听4个儿子,而是监听父元素,看触发事件的元素是哪个儿子,这就是事件委托。
可以监听还没有出生的儿子(动态生成的元素)。省监听器。