声明:本人的所有博客皆为个人笔记,作为个人知识索引使用,因此在叙述上存在逻辑不通顺、跨度大等问题,希望理解。分享出来仅供大家学习翻阅,若有错误希望指出,感谢!
事件流
事件流描述的是从页面接收事件的顺序
事件冒泡
- 事件开始由最具体的元素接收,然后逐级向上传播到较为不具体的节点
事件捕获
- 事件开始由最不具体的元素接收,然后逐级向下传播到最具体的节点
- 很少有人使用事件捕获,可以放心使用事件冒泡
DOM事件流
- DOM2级事件规定事件流包括三个阶段:事件捕获阶段、处于目标阶段、事件冒泡阶段
- 事件捕获为截获事件提供了机会,然后是实际的目标接收到事件,最后一个阶段是冒泡阶段,可以在这个阶段对事件做出相应
- 在DOM事件流中,实际的目标在捕获阶段不会接收到事件
- 多数支持DOM事件流的浏览器都实现了一种特定的行为:即使规范明确要求捕获阶段不会涉及事件目标,但浏览器都会在捕获阶段触发事件对象上的事件,结果就是:有两个机会在目标对象上操作事件
事件处理程序
相应某个事件的函数叫做事件处理程序,事件处理程序名字以“on”开头
HTML事件处理程序
<标签名 事件名="JavaScript代码">
例如: <input type="button" value="Click me" onclick="alert(value)">
- 此处JavaScript代码是一段字符串,故其中不可出现双引号,可用单引号代替,也不能出现未经转义的HTML语法字符
- 此处JavaScript代码中也可以调用页面其他地方定义的脚本
- 事件处理程序的代码在执行时,有权访问全局作用域中的任何代码
- 此处JavaScript代码实际上是一个动态函数,该动态函数使用with为自己拓展作用域
function(){
with(document){ //因此有权访问全局作用域中的任何代码
with(this){
…………
}
}
}
//如果当前元素是一个表单元素,则作用域还会包含访问表单元素的入口
function(){
with(document){
with(this.form){ //父元素
with(this){
…………
}
}
}
}
缺点:
- 存在时差问题,若html元素一出现就触发相应事件,此时事件处理程序有可能不具备运行条件
- 在不同浏览器中会导致不同的结果
- HTML与JavaScript代码紧密耦合
DOM0级事件处理程序
每个元素(包括window和document)都有自己的事件处理属性,这些属性通常全部小写,将这种属性的值设置为一个函数,就能指定事件处理程序
//以点击按钮为例
var btn = document.getElementById("myBtn"); //也可以用其他方法获取
btn.onclick = function(){
//事件处理程序
}
- 使用DOM0级方法指定的事件被认为是元素的方法,因此这种事件处理程序是在元素的作用域上运行的,程序中的this引用当前元素
- 以这种方法添加的事件处理程序在事件流的冒泡阶段被处理
- 通过将事件处理程序属性的值设置为null,就可以删除事件处理程序
DOM2级事件处理程序
var A = document.getElementById("元素ID"); //也可以用其他方法获取
//使用匿名函数作为事件处理函数
A.addEventListener("事件名",function(){ //事件名不以on开头
//事件处理程序
},布尔值); //第三个参数为一个布尔值,true:在捕获阶段调用事件处理程序,false:在冒泡阶段调用事件处理程序
//使用具体函数对象作为事件处理函数
A.addEventListener("事件名",函数对象,布尔值);
//removeEventListener()的参数与addEventListener()完全相同,一字不差,但若事件处理函数为匿名函数,则无法移除(因为多个相同的匿名函数不是同一个函数对象)
A.removeEventListener("事件名",函数对象,布尔值);
- 使用DOM2级方法指定的事件也被认为是元素的方法,在元素的作用域上运行,程序中的this引用当前元素
- DOM2级方法的优点是可以多次调用addEventListener()方法添加多个事件处理函数,多个事件处理函数会按照它们被添加的顺序被触发
- 大多数情况下,都将事件处理程序添加到事件流的冒泡阶段(既第三个参数设置为false),可以最大限度地兼容各种浏览器
IE事件处理程序
var A = document.getElementById("元素ID"); //也可以用其他方法获取
//使用匿名函数作为事件处理函数
A.attachEvent("on事件名",function(){
//事件处理程序
});
//使用具体函数对象作为事件处理函数
A.attachEvent("on事件名",函数对象);
//detachEvent()的参数与attachEvent()完全相同,一字不差,但若事件处理函数为匿名函数,则无法移除(因为多个相同的匿名函数不是同一个函数对象)
A.detachEvent("on事件名",函数对象);
使用attachEvent()方法添加的事件处理函数作用域为全局作用域,this等于window
attachEvent()方法可以为元素添加多个事件处理函数,多个事件处理函数会按照它们被添加的相反顺序被触发(注意是相反顺序)
跨浏览器的事件处理程序
//使用EventUtil对象的addHandler()方法添加事件处理函数,removeHandler()方法移除事件处理函数
var EventUtil = {
addHandler : function(element,type,handler){
if(element.addEventListener){ //DOM2
element.addEventListener(type,handler,false);
} else if(element.attachEvent){ //IE
element.attachEvent("on"+type,handler);
} else{ //其他方法都无效时默认采用DOM0级方法
element["on"+type] = handler;
}
},
removeHandler : function(element,type,handler){ //参数与addHandler()完全相同
if(element.removeEventListener){ //DOM2
element.removeEventListener(type,handler,false);
} else if(element.detachEvent){ //IE
element.detachEvent("on"+type,handler);
} else{ //其他方法都无效时默认采用DOM0级方法
element["on"+type] = null;
}
}
};
var A = document.getElementById("元素ID"); //也可以用其他方法获取
var handler = function(){
//事件处理程序
}
EventUtil.addHandler(A,"事件名",handler); //添加事件处理函数
EventUtil.removeHandler(A,"事件名",handler); //移除事件处理函数
事件对象
- 在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息
- 只有在事件处理程序执行期间,event对象才存在,一旦事件处理程序执行完毕,event对象会被销毁
DOM中的事件对象
兼容DOM的浏览器会将一个event对象传入事件处理程序中(无论DOM0还是DOM2)
event对象包含与创建它的特定事件有关的属性和方法,触发的事件类型不一样,可用的属性和方法也不一样
event共有属性
属性/方法 |
类型 |
说明 |
bubbles |
Boolean |
表明事件是否冒泡 |
cancelable |
Boolean |
表明是否可以取消事件的默认行为 |
currentTarget |
Element |
事件处理程序当前正在处理的那个元素 |
defailtPrevented |
Boolean |
true:已调用preventDefault() |
detail |
Integer |
与事件相关的细节信息 |
eventPhase |
Integer |
调用事件处理程序的阶段(1:捕获阶段,2:处于目标,3:冒泡阶段) |
preventDefault() |
Function |
取消事件的默认行为,cancelable为true时才可使用 |
stopImmediatePropagation() |
Function |
取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用 |
stopPropagation() |
Function |
取消事件的进一步捕获或冒泡,bubbles为true时才可使用 |
target |
Element |
事件的目标 |
isTrusted |
Boolean |
true:事件是通过浏览器生成的,false:事件是通过JavaScript创建的 |
type |
String |
被触发的事件的类型 |
view |
AbstractView |
与事件关联的抽象视图,等同于发生事件的window对象 |
在事件处理程序内部:
- this始终等于currentTarget
- target只包含事件的实际目标
- 如果直接将事件处理程序指定给了目标元素( A.οnclick=function(event){……} ),则this,currentTarget,target包含相同的值
如果事件处理程序存在于触发事件的元素的父元素中:
- currentTarget = 父元素
- this = 父元素
- target = 触发事件的元素(子元素)
一个函数处理多个事件
在需要通过一个函数处理多个事件时,可以使用type属性:
//将该函数作为事件处理函数与多个事件绑定
var handler = function(event){
switch(event.type){
case "事件名1":
事件处理程序1
break;
case "事件名2":
事件处理程序2
break;
…………
}
};
阻止特定事件的默认行为
- 使用event.preventDefault()
- 只有cancelable为true才能使用preventDefault()
停止事件传播
- 使用event.stopPropagation()
- stopPropagation()方法用于立即停止事件在DOM层次中的传播,既取消进一步的事件捕获或冒泡
IE中的事件对象
访问IE中的event对象的方法取决于指定事件处理程序的方法
- 在使用DOM0方法添加事件处理程序时,event对象作为window对象的一个属性存在
- 若事件处理函数是通过attachEvent()方法添加的,那么会有一个event对象作为参数传入事件处理函数
- 在使用attachEvent()的情况下,也可以使用window.event来访问event对象
event共有属性
属性/方法 |
类型 |
说明 |
cancelBubble |
Boolean |
默认false,将其设置为true即可取消事件冒泡(与DOM的stopPropagation()作用相同) |
returnValue |
Boolean |
默认true,将其设置为false即可取消事件默认行为(与DOM的preventDefault()作用相同) |
srcElement |
Element |
事件的目标(与DOM的target属性相同) |
type |
String |
被触发的事件的类型 |
- 因为事件处理函数的作用域是根据指定它的方式来确定的,所以不能认为this始终等于事件目标,最好使用srcElement更保险
跨浏览器的事件对象
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;
}
}
//以下为有关事件对象的操作
getEvent : function(event){ //获取事件对象
return event ? event : window.event;
},
getTarget : function(event){ //获取事件的目标
return event.target || event.srcElement;
},
preventDefault : function(event){ //取消事件默认行为
if(event.preventDefault){
event.preventDefault();
} else{
event.returnValue = false;
}
},
stopPropagation : function(event){ //取消事件捕获或冒泡
if(event.stopPropagation){
event.stopPropagation();
} else{
event.cancelBubble = true;
}
}
};
//使用方法
var A = document.getElementById("元素ID");
A.onclick = function(event){
event = EventUtil.getEvent(event); //获取事件对象
var target = EventUtil.getTarget(event); //获取事件的目标
EventUtil.preventDefault(event); //取消事件默认行为
EventUtil.stopPropagation(event); //取消事件捕获或冒泡
}