JavaScript与HTML之间的交互是通过事件实现的。
IE9,Firefox,Opera,Safari,Chrome全都已经实现了“DOM2级事件“模块的核心部分。IE8是最后一个仍然使用其专有事件系统的主要浏览器。
1 事件流
事件流描述的是从页面中接收事件的顺序。IE和Netscape开发团队提出差不多完全相反的事件流事件。
1.1 事件冒泡
IE的事件流叫做事件冒泡(even bubbling),即事件开始时由最具体的元素(文档中嵌套层次最深的那个节点)接收,然后逐级向上传播到较为不具体的节点(文档)。所有现代浏览器都支持事件冒泡。
1.2 事件捕获
Netscape提出的事件流称为事件捕获(event capturing)。事件捕获的思想是不太具体的节点应该更早接收到事件,而最具体的事件应该最后接收到事件。
1.3 DOM事件流
“DOM2级事件“规定的事件流包括三个阶段:事件捕获阶段,处理目标阶段和事件冒泡阶段。即使“DOM2级事件“规范明确要求捕获阶段不会涉及事件目标,但IE9,Safari,Chrome,Firefox和Opera9.5及更高版本都会在捕获阶段触发事件对象上的事件,结果,就是会有两个机会在目标对象上面操作事件。
2 事件处理程序
2.1 DOM0级事件处理程序
通过JS指定事件处理程序的传统方式,就是将一个函数赋值给一个事件处理程序属性。
var btn = document.getElementById('myBtn');
btn.onclick = function(){
alert('Clicked');
}
以这种方式添加的事件处理程序会在事件流的冒泡阶段被处理。
2.2 DOM2级事件处理程序
DOM2定义了两个方法,用于处理指定和删除事件处理程序的操作:addEventListener(),removeEventListener()
,所有DOM节点都包含这两个方法,并且它们都接受3个参数:要处理的事件名,作为事件处理程序的函数和一个布尔值。最后一个布尔值参数如果为true,表示在捕获阶段调用事件处理程序;如果是false,表示在冒泡阶段调用事件处理程序。
其中,注意addEventListener(),removeEventListener()
两个函数传入的必须是一个函数。并且大多数情况下,都是将事件处理程序添加到事件流的冒泡阶段,这样可以最大限度的兼容各种浏览器。
//跨浏览器的事件处理程序
var EventUtil = {
addHandler : function(element, type, handler){
if(element.addEventListener){
element.addEventListener(type, handler, false);
}else if(element.attachEvent){
element.attachEvent('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);
}
}
};
3 事件对象
在触发DOM上的某个事件时,会产生一个事件对象event,这个对象中包含着所有与事件有关的信息,包括导致事件的元素,事件的类型以及其他与特定事件相关的信息。
无论指定事件处理程序时使用什么方法,都会传入event对象。event.type属性表示的是事件类型。
与访问DOM中的event对象不同,要访问IE中的event对象有几种不同的方式,取决于指定事件处理程序的方法。在使用DOM0级方法添加事件处理程序时,event对象作为window对象的一个属性存在;若是使用attachEvent(),那么就会有一个event对象最为参数被传入事件处理程序函数中。
var EventUtil = {
addHandler : ......
getEvent : function(event){
return event ? event : window.event;
}
};
4 事件类型
4.1 UI事件
UI事件类型 | 解释 | 备注 |
---|---|---|
load | 当页面加载后在window上面触发 | |
select | 当用户选择文本框< input>或< texterea>中的一或多个字符时触发 | |
error | 当发生JS错误时在window上面触发 | |
resize | 当窗口或框架的大小变化时在window或框架上面触发 | |
scroll | 当用户滚动带滚动条的元素中的内容时在该元素上面触发 |
4.1.1 scroll事件
在混杂模式下,可以通过body元素的scrollLeft和scrollTop来监控到这一变化;而在标准模式下,除Safari之外的所有浏览器都会通过html元素来监控这一反应(Safari仍然是基于body滚动的)
我的另外一篇博客也有讲到,点这里
4.1.2 焦点事件
这一类事件中最主要的两个就是focus和blur,所有的浏览器都支持这两个事件,但这两个事件的最大的问题就是它们不冒泡。
4.1.3 鼠标和滚轮事件
DOM3级事件中定义了9个鼠标事件
鼠标事件名称 | 解释 | 备注 |
---|---|---|
click | 在用户单击鼠标按钮(一般是左边按钮)或者按下回车键时触发 | |
dbclick | 在用户双击鼠标按钮(一般是左边按钮) | |
mousedown | 在用户按下任意鼠标按钮时触发 | |
mouseenter | 在鼠标光标从元素外部首次移动到元素范围之内时触发 | 这个事件不冒泡,而且光标移动到后代元素不会触发 |
mouseleave | 在位于元素上方鼠标光标移动到元素范围之外时触发 | 同上 |
mousemove | 当鼠标指针在元素内部移动时重复地触发 | |
mouseout | 在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发 | |
mouseover | 在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发 | |
mouseup | 在用户释放鼠标按钮时触发 |
只有在同一个元素上相继触发mousedown和mouseup事件,才会触发click事件。类似的,只有触发两次click事件才能触发一次dbclick事件。
4.1.3.1 客户区坐标位置
鼠标事件都是在浏览器视口中的特定位置上发生的。这个位置信息保存在事件对象的clientX和clientY属性中。所有浏览器都支持这两个属性。它们的值表示事件发生时鼠标指针在视口中的水平和垂直坐标。注意:这个值不包括页面滚动的距离。
var myDiv = document.getElementById('myDiv');
EventUtil.addHandler(myDiv, 'click', function(){
event = EventUtil.getEvent(event);
alert('Client coordinate:'+ event.clientX + ","+event.clientY);
})
4.1.3.2 页面坐标位置
通过客户区坐标能够知道鼠标是在视口中什么位置发生的。而页面坐标通过事件对象的pageX和pageY属性,能够告诉你事件是在页面中什么位置发生的。
在页面没有滚动的情况下,pageX和pageY的值与clientX与clientY的值相等。
IE8及更早的版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。
var myDiv = document.getElementById('myDiv');
EventUtil.addHandler(myDiv, 'click', function(event){
event = EventUtil.getEvent(event);
var pageX = event.pageX,
pageY = event.pageY;
if(pageX == undefined){
pageX = event.clientX + (document.documentElement.scrollLeft || document.body.scrollLeft);
}
if(pageY == undefined){
pageY = event.clientY + (document.documentElement.scrollTop || document.body.scrollTop);
}
alert('page coordinates:' + pageX + ',' + pageY);
})
4.1.3.3 屏幕坐标位置
通过screenX和screenY属性可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。