事件这个东西呢?是一个很神奇的东西,搞的我很烦 无论是在Android端还是前端。今天巧借这点时间呢?就准备来写一写这个东西。先写一篇前端的事件,然后再转向Android端写一篇Android端的事件 perfect...
一、 什么叫事件流
事件流的描述呢?很简单:就是描述从页面接收到事件的顺序。现今主流的两大阵营对此提出了两种相反的事件流:ie提出的称之为事件冒泡;Netscape communicator提出的则是事件捕获。那么什么是事件冒泡和事件捕获呢?
-
事件冒泡
IE的事件流叫做事件冒泡,说白了冒泡就是从嵌套最深的那个节点接收,然后逐级向上冒泡直到document的过程。用下面的html为例子:
<!DOCTYPE html>
<html>
<head>
<title>我是测试</title>
</head>
<body>
<div >click Me</div>
</body>
</html>
复制代码
如果你单击了div元素,那么这个click事件就这么传递: 1、 div 2、 body 3、 html 4、document 也就是说,当我们点击了div元素之后,click事件首先在div元素上面发生,这个元素就是我们单击的元素。然后click事件就顺着DOM树向上传播,在每一级上面都会发生,一直传到document。
-
事件捕获
Netscape communicator团队提出了另一种事件流叫做事件捕获。事件捕获的过程呢?则是从document开始一直传递到div的过程: 1、document 2、 html 3、 body 4、 div 示意图如下:
-
DOM的事件流
通常的事件流包括三个步骤:事件捕获阶段、处于目标阶段和事件冒泡阶段。用前面的html表示,大概就是这样。
二、 事件的处理程序
事件呢?就是:用户或者浏览器自身执行的某种动作。比如click,load和mouseover。而相应某个事件的函数叫做事件处理程序。一般都是
on
开头的,onclick就是click的处理程序、onload就是load的处理程序等等...
首先 我们直接用代码来写主要的几种类型:
1、 html事件处理程序:
<button id="myBtn1" onclick="showMessage()">我是 html事件处理程序</button>
function showMessage(){
alert("hello my friends!")
}
复制代码
2、 Dom0事件处理程序:
<button id="myBtn2">我是dom0事件处理程序</button>
var btn2 = document.getElementById("myBtn2");
btn.onclick = function(){
alert("hello my friends!");
}
btn.onclick = null; //移除事件
复制代码
3、 Dom2事件处理程序:
这里和前面不同,dom2定义了两个方法:addEventListener()和removeEventListener()分别用来绑定和删除事件。所有的dom节点都包含这个方法,并且它接受三个参数:处理的事件名、作为事件处理的函数和一个布尔值。如果这个布尔值是true,表示在捕获阶段调用事件程序;如果是false,则表示在冒泡阶段调用事件处理程序。
事件绑定如下:
<button id="myBtn">我是dom2事件处理程序</button>
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert("hello klivitam!")
},false)
复制代码
关于事件绑定和移除有这么几个要注意的点:
- 事件多次绑定
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert("hello klivitam!")
},false)
btn.addEventListener("click",function(){
alert("123456")
},false)
复制代码
如果重复进行添加事件的话,这样会先出按照顺序 先显示
hello klivitam
,然后再显示
123456
。
- 事件移除 先看下面一段代码
var btn = document.getElementById("myBtn");
btn.addEventListener("click",function(){
alert("hello klivitam!")
},false)
btn.removeEventListener("click",function(){
alert("hello klivitam!")
},false)
复制代码
我们知道:利用addEventListener()绑定的事件,需要用removeEventListener()来将事件的监听移除,并且removeEventListener()的参数必须和addEventListener()的参数相同。这里我们虽然看似两者是相同的,但是并不能移除。这是值得注意的,针对这种情况,我们应该这么写:
var handle = function(){
alert("hello klivitam!")
}
var btn = document.getElementById("myBtn");
btn.addEventListener("click",handle,false)
btn.removeEventListener("click",handle,false)
复制代码
3、 IE事件处理程序:
ie中存在和dom中想同的两个方法:attachEvent和detachEvent。这两个方法接受想同的两个参数:事件处理程序的名称与事件处理程序函数。 首先我们先写一个绑定的实例:
var btn2 = document.getElementById("myBtn2");
btn2.attachEvent("onclick",function(){
alert(window === this);
})
btn2.attachEvent("onclick",function(){
alert("boy");
})
复制代码
同样和dom2的一样的操作,这里只不过函数名变了。这里值得注意的是:
window和this相等
。当点击btn2元素的时候,首先会提示true,然后再提示boy。并且在移除代码的时候,和dom2的操作一样
var btn2 = document.getElementById("myBtn2");
var handle = function(){
alert("hello klivitam!")
}
btn2.attachEvent("onclick",handle)
btn2.detachEvent("onclick",handle)
复制代码
4、 跨浏览器的事件处理程序:
前面说了这么多方面的事件处理程序,那么我们在进行开发的时候很可能会需要适配很多浏览器。我们在每次事件绑定的时候,肯定要考虑到诸多版本,诸多内核的浏览器。为了解决这种逻辑,我们就可以进行封装处理。我在这里是这样进行处理的:
var EventUtils = {
addHandler: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;
}
}
removeHandler: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;
}
}
}
复制代码
首先,我们在绑定事件的时候呢?绑定事件的时候首先判断是否支持dom2的事件处理程序,如果不支持,那么继续判断是否支持ie的事件处理程序,如若还不支持就只能用通用的事件处理程序。解绑的时候也是一样,先判断是否支持dom2事件处理程序,接着判断ie的事件处理程序,最后在都不支持的情况下使用通用的事件处理程序。
我们在使用的时候就可以这样写一下就好了:
var btn2 = document.getElementById("myBtn2");
var handle = function(){
alert("hello klivitam!");
}
EventUtils.addHandler(btn2,"click",hander);
EventUtils.removeHandler(btn,"click",hander);
复制代码
当然这个封装还室友点瑕疵的,比如不知道this的指向等等,当然 我在后续的文章中会继续的去讨论封装这个组件的。
三、 事件的对象
我们知道在触发dom上的某个事件对象的时候,这个对象会包含着所有与事件有关的信息。包括事件的元素、事件的类型以及其他与特定事件相关的信息。
-
dom的事件对象
兼容dom的浏览器会将一个event对象传到事件处理程序中。例如:
btn.addEventListener("click",function(e){
console.log(e);
},false)
btn.onclick = function(e){
console.log(e);
};
复制代码
属性/方法 | 类型 | 读写 | 说明 |
---|---|---|---|
bubbles | boolean | 只读 | 表明事件是否冒泡 |
cancelable | boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 其事件的处理程序正在处理程序的那个元素 |
defaultPrevented | boolean | 只读 | 为true表示已经调用了preventDefault(dom3新增的) |
detail | Integer | 只读 | 与事件相关的详细细节 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1表示捕获,2处于目标,3处于冒泡 |
preventDefault() | Function | 只读 | 取消事件的 默认行为,如果cancelable为true才能使用这个方法 |
stopImmediatePropagation | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用(dom3新增) |
stopPropagation | Function | 只读 | 取消事件的进一步捕获或者冒泡。如果cancelable为true的时候,才能使用这个方法 |
target | Element | 只读 | 事件的目标 |
trusted | Boolean | 只读 | 为true表示事件是浏览器生成的。为false表示事件又开发者通过js创建的(dom3新增的) |
type | String | 只读 | 被触发事件的类型 |
view | abstractview | 只读 | 与事件相关联的抽象视图,等同于发生事件的window对象 |
上面表格中值得注意三点的就是:
-
this是始终等于currentTarget的值,而target则只包含事件的实际目标