事件就是Web浏览器通知应用程序发生了什么事情。DOM定义了一些事件,允许开发者通过给事件绑定事件处理函数,来指定当触发了该事件时,所要调用的函数。首先理解什么是事件流:
一.事件流:
事件流描述的是从页面中接受事件的顺序。事件流分为两种:事件冒泡流,事件捕获流。
- 事件冒泡:事件由文档中嵌套层次最深的那个节点接受,再逐级向上传播至文档(document);
- 事件捕获:事件由文档(document)接收,再逐级向下传播至嵌套层次最深的节点。
注意:
事件的传播分为三个阶段:捕获阶段,目标阶段(事件在目标对象上触发),冒泡阶段。
二.事件处理程序:
1.HTML事件处理程序:
即设置HTML标签属性为事件处理程序。代码如下:
<input type="button" <span style="color:#3333ff;">οnclick="alert('HTML事件处理程序')" value="按钮"/>
也可以将函数作为HTML标签属性,代码如下:
<input type="button" id="btn" <span style="color:#3333ff;">οnclick="showMessage();" value="按钮" />
<script type="text/javascript">
function showMessage(){
alert("HTML事件处理程序");
}
</script>
通过代码可以发现,HTML事件处理程序将HTML和JS混合在一起。而客户端编程的通用风格是保持HTML内容和JS行为分离,所以在开发过程中,应避免使用此方法。
2.DOM0级事件处理程序:
即把一个函数赋值给一个事件的处理程序属性。代码如下:
<input type="button" id="btn1" value="按钮1" /></span>
<script type="text/javascript">
var btn1 = document.getElementById("btn1");
<span style="color:#3333ff;">btn1.onclick</span> = function(){
alert("DOM0级事件处理程序");
}
</script>
通过代码可以发现,DOM0级事件处理程序将HTML和JS分离开了,并且拥有跨浏览器的优势。
3.DOM2级事件处理程序:
定义了两个方法用于注册和删除事件处理程序:
- addEventListener()方法:用于注册事件处理程序;
- removeEventListener()方法:用于删除事件处理程序。
两个方法都接收三个参数:
- 要处理的事件名,eg:"click";
- 作为事件处理程序的函数;
- 布尔值,为true时,表示在捕获阶段调用事件处理程序;为false时,表示在冒泡阶段调用事件处理程序。默认为false。
为input对象的click事件注册事件处理程序,使用addEventListener()方法,代码如下:
<input type="button" id="btn2" value="按钮2" />
var btn2 = document.getElementById("btn2");
btn2.addEventListener("click",showMessage1,false);
function showMessage1(){
alert("DOM2级事件处理程序");
}
要想删除注册了的事件处理程序,使用removeEventListener()方法,参数应该和注册事件处理程序时参数一样,代码如下:
btn2.removeEventListener("click",showMessage1,false);
注意:DOM2级事件处理程序在IE中是不支持的,下面介绍IE中的事件处理程序。
4.IE事件处理程序:
定义了两个方法用于注册和删除事件处理程序:
- attachEvent()方法:用于注册事件处理程序;
- detachEvent()方法:用于删除事件处理程序。
两个方法都接收两个参数:
- 要处理的事件名,eg:"onclick";
- 作为事件处理程序的函数。
为input对象的onclick事件注册事件处理程序,使用attachEvent()方法,代码如下:
<input type="button" id="btn3" value="按钮3" />
var btn3 = document.getElementById("btn3");
btn3.attachEvent("onclick",showMessage2);
function showMessage2(){
alert("IE事件处理程序");
}
要想删除注册了的事件处理程序,使用detachEvent()方法,参数应该和注册事件处理程序时参数一样,代码如下:
<span style="font-family:Comic Sans MS;font-size:14px;color:#3333ff;">btn3.detachEvent("onclick",showMessage2);</span>
注意:由于IE8以及更早的浏览器版本只支持事件冒泡,所以与DOM2级的两个方法不同,IE事件处理程序不用接收第三个布尔值参数。
扩展内容:
- DOM0级事件处理程序,DOM2级事件处理程序以及IE事件处理程序都能多次使用,给同一对象的注册同一个事件的多个事件处理程序。然而,区别在于DOM0级将会覆盖该对象的该事件的已注册的事件处理程序,而DOM2级以及IE中的事件处理程序不会修改或覆盖该对象的该事件的已注册的事件处理程序,且当对象该事件发生时,所有该事件注册的事件处理程序将会按照注册的顺序调用。
- DOM0级事件处理程序具有跨浏览器的优势,然而,DOM2级事件处理程序在IE中不支持,而IE事件处理程序只在IE及Opera中支持,所有就需要跨浏览器的事件处理程序。
5.跨浏览器的事件处理程序:
将跨浏览器的事件处理程序通过能力检测等方式,将方法封装在一个对象中,代码如下:
<input type="button" id="btn4" value="按钮4" />
var domEvent = {
//注册事件处理程序,传入3个参数,表示对象,事件类型,函数
addListener:function(ele,type,hander){
if(ele.addEventListener){
ele.addEventListener(type,hander,false);
}else if(ele.attachEvent){
ele.attachEvent("on"+type,hander);
}else{
ele["on"+type] = hander;
}
},
//删除事件处理程序
removeListener:function(ele,type,hander){
if(ele.removeEventListener){
ele.removeEventListener(type,hander,false);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,hander);
}else{
ele["on"+type] = null;
}
}
}
var btn4 = document.getElementById("btn4");
domEvent.addListener(btn4,"click",showMessage3);
function showMessage3(){
alert("跨浏览器的事件处理程序");
}
其中,有几个细节需要注意:
- 传入的type参数应该为不带on的时间类型,如"click";
- 在既不支持DOM2级事件处理程序,又不支持IE事件处理程序的浏览器中,使用DOM0级事件处理程序时,由于ele."on"+type不符合JS语法,所以需要使用“[]”代替点运算符。
三.事件对象:
事件对象(event):在触发DOM上的事件都会产生一个事件对象。然而DOM中的事件对象与IE中的事件对象是不一样的,下面开始介绍这两种事件对象。
1.DOM中的事件对象(event):
列举几个常用的event对象的属性和方法:
- type属性:获取事件类型;
- target属性:获取事件目标;
- stopPropagation()方法:阻止事件冒泡;
- preventDefault()方法:阻止事件的默认行为;
首先创建一个div中,并在div中添加一个input元素,为div及input的click事件注册事件处理程序,示例代码如下:
<div id="box">
<input type="button" id="btn5" value="按钮5" />
</div>
var box = document.getElementById("box");
var btn5 = document.getElementById("btn5");
domEvent.addListener(box,"click",showMessage5);
domEvent.addListener(btn5,"click",showMessage4);
function showMessage4(event){
alert(event.type);
alert(event.target);
}
function showMessage5(){
alert("这是box调用的方法");
}
发现:首先弹出click,然后弹出[object HTMLInputElement],最后弹出“这是box调用的方法”。可以看出,click事件从input节点冒泡到了其父节点div,并触发了该节点的click事件的事件处理程序。可以使用stopPropagation()方法来阻止事件冒泡,改变showMessage4(),代码如下:
function showMessage4(event){
alert(event.type);
alert(event.target);
event.stopPropagation();
}
2.IE中的事件对象:
列举几个常用的event对象的属性:
- type属性:获取事件类型;
- srcElement属性:获取事件目标;
- cancelBubble属性:阻止事件冒泡(true:阻止冒泡;false:不阻止冒泡);
- returnValue属性:用于组织时间的默认行为(设置为false表示不阻止事件的默认行为,默认为true)。
将上文中的showMessage4()方法进行修改,代码如下:
<pre name="code" class="html">function showMessage4(event){
alert(event.type);
alert(event.srcElement);
event.cancelBubble;
}
发现,DOM中的事件对象与IE中的事件对象在属性和方法上有一定的差别,这就涉及到了跨浏览器的问题。将DOM的事件对象与IE中的事件对象中的属性和方法封装到一个对象中,可以解决跨浏览器的问题,类似在跨浏览器的事件处理程序的部分里封装的对象objectEvent。代码如下:
var objectEvent = {
//跨浏览器注册事件处理程序
addListener:function(ele,type,hander){
if(ele.addEventListener){
ele.addEventListener(type,hander,false); //如果浏览器支持DOM2级事件处理程序,则调用DOM2级事件处理程序
}else if(ele.attachEvent){
ele.attachEvent("on"+type,hander); //IE事件处理程序
}else{
ele["on"+type] = hander; //DOM0级事件处理程序
}
},
//跨浏览器删除事件处理程序
removeListener:function(ele,type,hander){
if(ele.removeEventListener){
ele.removeEventListener(type,hander,false);
}else if(ele.detachEvent){
ele.detachEvent("on"+type,hander);
}else{
ele["on"+type] = null;
}
},
//跨浏览器获取事件对象event
getEvent:function(e){
return e = e || window.event; //由于DOM与IE中的时间对象有区别,并且在IE中必须通过window.event得到
// return e?e:window.event;
},
//跨浏览器获取事件对象的类型
getType:function(e){
return e.type;
},
//跨浏览器获取事件对象的目标
getTarget:function(e){
return e.target || e.srcElement;
// e.target?e.target:e.srcElement;
},
//跨浏览器阻止事件冒泡
stopPropagation:function(e){
if(e.stopPropagation){
e.stopPropagation();
}else if(e.cancelBubble){
e.cancelBubble;
}
},
//跨浏览器阻止事件的默认行为
preventDefault:function(e){
if(e.preventDefault){
e.preventDefault();
}else if(e.returnValue){
e.returnValue;
}
}
}
var btn5 = document.getElementById("btn5");
var box = document.getElementById("box");
objectEvent.addListener(box,"click",showMessage5);
objectEvent.addListener(btn5,"click",showMessage4);
function showMessage4(event){
event = objectEvent.getEvent(event);
alert(objectEvent.getType(event));
alert(objectEvent.getTarget(event).nodeName);
objectEvent.stopPropagation(event);
}
function showMessage5(){
alert("这是box的调用的方法");
}