DOM 事件模型
事件是用户或者浏览器自己执行的某种动作,比如点击(click)按钮等,这里的click就是事件的名称。JS与html之间的交互是通过事件实现的,DOM支持大量的事件。
我们从点击事件来进行描述
事件模型
一个事件发生后,会在子元素及父元素之间进行传播(propagation),这种传播分为三个阶段。
- 由外向内找监听函数就是事件捕获
- 在目标节点触发事件
- 由内而外找监听函数就是事件冒泡
事件传播的最上层对象是window,上例的事件传播顺序,在捕获阶段依次为window、document、html、body、父节点、目标节点,在冒泡阶段依次为目标节点、父节点、body、html、document、window。
代码如下
<div class="爷爷">
<div class="爸爸">
<div class="儿子">
文本
</div>
</div>
</div>
有这样的一个网页,即 .爷爷>.爸爸>.儿子,分别添加事件监听 fnYe / fnBa / fnEr
提问1: 点击了谁?
点击文字, 算不算点击儿子
点击文字, 算不算点击爸爸
点击文字, 算不算点击爷爷
答: 都算
提问2: 调用顺序? 点击文字最先调用fnYe/fnBa/fnEr中的哪一个函数?
答: 都行. IE5调用顺序为fnEr->fnBa->fnYe, 网景调用顺序为fnYe->fnBa->fnEr
因此W3C在2002年发布了标准, 文件名为DOM Level 2 Events Specification, 规定浏览器同时支持两种调用顺序.首先按爷爷->爸爸->儿子顺序看有没有函数监听, 然后按儿子->爸爸->爷爷顺序看有没有函数监听.
因此, 用专业术语来说这2种顺序分别就是DOM事件模型的事件捕获和事件冒泡.一个事件发生后,会在子元素和父元素之间传播(propagation)。
由外向内找监听函数, 叫事件监听.
由内向外找监听函数, 叫事件冒泡.
其中文字(示例代码中)就是事件监听和事件冒泡的目标.因此DOM事件模型分为3个阶段:
(1)捕获阶段:事件从window对象自上而下向目标节点传播的阶段(示例代码中简化为: 爷爷->爸爸->儿子);
(2)目标阶段:真正的目标节点正在处理事件的阶段;(示例代码中: 文字)
(3)冒泡阶段:事件从目标节点自下而上向window对象传播的阶段(示例代码中简化为: 儿子->爸爸->爷爷)。
- 事件捕获,是指按 爷爷=>爸爸=>儿子 的顺序看有没有函数监听
- 事件冒泡,是指按 儿子=>爸爸=>爷爷 的顺序看有没有函数监听
从外向内找监听函数,叫* 事件捕获,从内向外找监听函数,叫事件冒泡
取消冒泡和阻止默认事件
取消冒泡
- event.stopPropagation()可中断冒泡,浏览器不再向上走。
【W3C标准event.stopPropagation();但不支持IE9以下版本】
【IE独有(谷歌也实现了)event.cancelBubble = true;】
function stopBubble(e) {
if(e && e.stopPropagation) { //非IE
e.stopPropagation();
} else { //IE
window.event.cancelBubble = true;
}
}
阻止默认事件
- 默认事件——表单提交,a标签跳转,右键菜单等
- 方法:
return false;以对象属性的方式注册的时间才生效
event.preventDefault()W3C标注,IE9以下不兼容
event.returnValue = false;兼容IE
/假定有链接<a href="http://baidu.com/" id="testA" >baidu.com</a>
var a = document.getElementById("testA");
a.onclick =function(e){
if(e.preventDefault){
e.preventDefault();
}else{
window.event.returnValue == false;
}
}
事件委托
什么是事件委托?
事件委托就是利用事件冒泡,只制定一个时间处理程序,就可以管理某一类型的所有事件。我用取快递来解释这个现象: 有三个同事预计会在周一收到快递。为签收快递,委托给前台代为签收。这种方案还有一个优势,那就是即使公司里来了新员工(不管多少),前台也会在收到寄给新员工的快递后核实并代为签收。
应用案例
案例1:当我们写代码时,要监听某个div里面的一百个buttom按钮的监听事件,该如何快捷操作呢?
答:给多个按钮添加监听事件,监听他们的祖先即可。
案例2:当我们写代码时,要监听一个在未来创建的元素的监听事件,该怎么操作呢?
答:给不存在的元素添加监听事件,监听他们的祖先啊。
综合上面两个的案例的优点:省监听数;可以监听动态元素