事件流描述的是从页面中接收事件的顺序,IE和Netscape提出来差不多完全相反的事件流的概念,IE事件流是事件冒泡流,Netscape事件流是事件捕获流。
IE的事件流叫做事件冒泡,即事件开始时由最具体的元素(文档中嵌套最深的那个节点)接收,然后逐级向上(一直到文档);如下代码:
<div id = "div"> <span id="span"> <a id="aTag">事件测试</a> </span></div>
JS如下:
document.getElementById("aTag").addEventListener('click',aTag);document.getElementById("span").addEventListener('click',span);document.getElementById("div").addEventListener('click',div);function aTag(e) { alert("点击的是a标签");}function span(e) { alert("点击的是span标签");}function div(e) { alert("点击的是div标签");}
当单击 “事件测试”文字后,那么click事件会按照如下顺序传播;
1)先打印出:点击的是a标签
2) 再打印出:点击的是span标签
3) 最后打印出:点击的是div标签
4) 最后肯定是document文档。
所有现代浏览器都支持事件冒泡。
事件捕获与事件冒泡事件流正好相反的顺序,事件捕获的事件流是最外层逐级向内传播,也就是先document,然后逐级div标签 ,span标签 , a标签;
上面的JS代码改成如下:
document.getElementById("div").addEventListener('click',div,true);document.getElementById("aTag").addEventListener('click',aTag,true);document.getElementById("span").addEventListener('click',span,true);
第三个参数设置为true,即为捕获事件,默认为false;否则的话,事件流还是和上面的一样,因为不管是在IE还是标准浏览器下,事件冒泡浏览器都支持的。
DOM2级事件规定的事件流包括三个阶段,分别是:事件捕获阶段,处于目标阶段和事件冒泡阶段。示意图就不画了,具体的可以看看书。
如下代码是DOM0级事件处理程序:
var btn = document.getElementById("btn");btn.onclick = function(){ alert("Clicked");};
使用DOM0级方法指定的事件处理程序被认为是元素的方法,处理程序是在元素的作用域进行的,程序中this是引用的是当前元素。
<div id="btn">btn</div>var btn = document.getElementById("btn");btn.onclick = function(){ alert(this.id); // 弹出btn}
单击元素btn后,通过this.id取得元素的属性id,还可以通过this访问元素的任何属性和方法,以这种方式添加的事情处理程序在事件流的冒泡阶段处理。
也可以删除通过DOM0级方法指定的事件处理程序,只要将事件处理程序的属性值设置为null即可。
btn.onclick = null; // 删除事件处理程序;
如下JS代码改成如下:
var btn = document.getElementById("btn");btn.onclick = function(){ alert(this.id);}btn.onclick = null;
再单击btn后,没有任何反应;
DOM2级事件定义了2个方法,用于处理指定和删除事件处理程序的操作;
addEventListener()和removeEventListener()。所有DOM节点都包含这两个方法,他们包含三个参数,第一个参数为事件类型;第二个参数为事件函数,第三个参数为布尔值,如果是true的话,说明是事件流是捕获事件,如果是false的话,那么事件流是冒泡事件;
比如如上的btn代码,我们改成如下:
var btn = document.getElementById("btn");btn.addEventListener('click',function(e){ alert(this.id);},false);
上面的点击事件是在冒泡阶段被触发,与DOM0级方法一样,这里添加的事件处理程序也是在其依副的元素作用域中运行,使用DOM2级添加事件处理程序的好处是可以添加多个事件处理程序,如下代码:
var btn = document.getElementById("btn");btn.addEventListener('click',function(e){ alert(this.id);},false);btn.addEventListener('click',function(e){ alert("我是来测试的");},false);
上面的代码被弹出2次对话框,而在DOM0级是不可以的;它永远是执行最后一次的。
addEventListener添加的事件只能使用removeEventListener来删除相对应的事件,那么如上的JS不能按照上面的方式来编写哦!需要给定义一个函数;如下:
btn.addEventListener('click',handler,false);function handler(e){ alert(this.id);}
可以使用如下方式对click事件删除;如下代码:
btn.removeEventListener(‘click’,handler);
上面的是在标准浏览器下处理的事件,下面我们来看看在IE下处理的事件;
IE实现了与DOM类似的2个方法,分别是attachEvent()和detachEvent(),这两个方法只接受2个参数,第一个参数是事件名称,第二个参数是要处理的函数;由于IE8及更早版本只支持事件冒泡,所以通过attachEvent()添加的事件处理程序会被添加到冒泡阶段;
下面是IE事件处理程序的代码如下:
btn.attachEvent('onclick',handler);function handler(e){ alert(this); // window}
注意:attachEvent的事件名称是onclick,而addEventListener的事件名称是click,且IE中使用的attachEvent()与使用DOM0级方法的的主要区别在于事件处理程序的作用域,在使用dom0级情况下,事件处理程序在其所属元素的作用域内运行,在使用attachEvent()方法的情况下,事件处理程序在全局作用域下运行,其中的this等于window。
与addEventListener一样,attachEvent也可以注册多个点击click事件,如下代码:
btn.attachEvent('onclick',function(e){ alert("1");});btn.attachEvent('onclick',function(e){ alert("2");});
但是与Dom方法不同的是,这些事件处理程序不是以添加他们的顺序执行,而是以相反的顺序触发,比如如上代码,会先弹出2,然后弹出1对话框;
使用attachEvent注册的事件只能使用detachEvent()方法来移除;
下面我们可以来编写跨浏览器的事件处理程序;代码如下:
var EventUtil = { addHandler: function(element,type,handler) { if(element.addEventListener) { element.addEventListener(type,handler,false); }else if(element.attachEvent) { element.attachEvent("on"+type,handler); }else { element["on" +type] = handler; } }, removeHandler: function(element,type,handler){ if(element.removeEventListener) { element.removeEventListener(type,handler,false); }else if(element.detachEvent) { element.detachEvent("on"+type,handler); }else { element["on" +type] = null; } }};
下面我们可以使用这个封装的函数代码来测试之前的代码了,代码改成如下所示:
function handler(){ alert(1);}EventUtil.addHandler(btn,'click',handler);
在IE或者标准浏览器下都会弹出1;如果我们需要移除click事件的话,我们可以使用如下代码:
EventUtil.removeHandler(btn,’click’,handler);
然后在标准浏览器下或者IE下点击btn元素都没有反应;
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息;包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。我们来看看dom0级和dom2级的事件对象Event;
比如如下代码:
var btn = document.getElementById("btn");btn.onclick = function(e){ console.log(e);}
打印如下:
下面我们来看看最基本的成员的含义吧;如下:
属性/方法 | 类型 | 含义 |
bubbles | Boolean | 事件是否冒泡 |
cancelable | Boolean | 是否可以取消事件的默认行为 |
currentTarget | Boolean | 事件处理程序当前正在处理事件的那个元素 |
defaultPRevented | Boolean | 为true 表示已经调用了preventDefault() |
detail | Integer | 与事件相关的细节信息 |
eventPhase | Integer | 调用事件处理程序的阶段:1表示捕获阶段,2表示“处于目标”,3表示冒泡阶段 |
preventDefault() | Function | 取消事件的默认行为。如果cancelable是true,则可以使用这个方法 |
stopImmediatePropagation() | Function | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用 |
stopPropagation() | Function | 取消事件的进一步捕获或冒泡。如果bubbles为true,则可以使用这个方法 |
target | Element | 事件的目标 |
type | String | 被触发的事件的类型 |
view | AbstractView | 与事件关联的抽象视图。等同于发生事件的window对象 |
在事件处理程序内部,this始终等于currentTarget值,即currentTarget是指当前被触发或者说正在处理事件的那个元素,而target是指当前的目标元素;比如如下代码,对btn按钮触发点击事件,那么e.currentTraget指向了this,e.target也指向了this;如下代码:
var btn = document.getEleme
新闻热点
疑难解答