1.1 事件冒泡
事件开始的时候从最具体的元素接收,然后逐级向上传播到较为不具体的节点。
1.2 事件捕获
事件捕获与冒泡相反,首先由不具体的节点接收,最后是最具体的节点接收事件。
注意: ie的事件流是事件冒泡。由于老版本的浏览器不支持事件捕获,因此更加建议使用事件冒泡,有特殊需要的时候在使用事件捕获。
1.3 DOM事件流
DOM2级事件规定的事件流包含三个阶段:事件捕获阶段,处于目标阶段和事件冒泡阶段。首先发生事件捕获,然后是实际目标接收到时间,最后是事件冒泡阶段。
2.1 HTML事件处理程序
通过HTML指定事件处理程序。
type="button" value="click me" onclick="alert('hello !')">
HTML与事件处理函数紧密耦合,一旦改动,改动地方较多,不满足结构、样式、行为分离。
2.2 DOM0级事件处理程序
使用js指定事件处理程序
var btn = document.getElementById("oneBtn");
btn.onclick = function() {
alert("hello world !");
}
// 删除事件处理程序
btn.onclick = null;
该方法简单,跨浏览器。所以至今使用仍然很广泛。
2.3 DOM2级事件处理程序
指定了两个方法来进行添加和删除时间处理程序。addEventListener(eventType, fnname, bool ) , removeEventListener( eventType, fnname, bool )
bool: true表示在捕获阶段调用事件处理函数,false表示在冒泡阶段调用。
注意:使用DOM2级方法可以添加多个事件处理程序。通过addEventListener添加的事件监听必须使用removeEventListener来移除。
2.4 IE事件处理程序
IE实现了与DOM中类似两个方法: attachEvent( eventType,handler )和detachEvent( eventType,handler ) 。
handler: 事件处理函数
注意:通过attachEvent添加的事件处理程序是在全局作用域下运行。所以 this==window。此外,attachEvent添加的多个事件处理程序触发顺序是相反的。
2.5 跨浏览器的事件处理程序
var eventUtil = {
addHandler: function(ele, type, handler) {
if(ele.addEventListener) {
ele.addEventListener(type, handler, false);
} else if(ele.attachEvent) {
ele.attachEvent('on'+type, handler);
} else {
ele['on'+type] = handler;
}
},
removeHandler: function(ele, type, handler) {
if(ele.removeEventListener) {
ele.removeEventListener(type, handler, false);
} else if(ele.detachEvent) {
ele.detachEvent('on'+type, handler);
} else {
ele['on'+type] = null;
}
}
}
3.1 DOM中的事件对象
无论是DOM0级或DOM2级方法添加事件处理程序,都会传入event对象。event对象包含与创建它的特定事件的属性和方法。
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
bubbles | Boolean | 只读 | 表明事件是否冒泡 |
cancelable | Boolean | 只读 | 表明是否可以取消事件的默认行为 |
currentTarget | Element | 只读 | 表明事件处理程序当前正在处理的元素 |
defaultPervented | Boolean | 只读 | 为true表示已经调用了preventDefault()方法 |
detail | Integer | 只读 | 表示与事件相关的细节信息 |
eventPhase | Integer | 只读 | 调用事件处理程序的阶段:1表示捕获阶段,2表示目标阶段,3表示冒泡阶段 |
preventDefault() | Function | 只读 | 取消事件的默认行为 |
stopImmediatePropagation() | Function | 只读 | 取消事件的进一步捕获或冒泡,同时阻止任何事件处理程序被调用 |
stopPropagation() | Function | 只读 | 阻止事件进一步捕获或冒泡 |
target | Element | 只读 | 目标元素 |
type | String | 只读 | 被触发的事件类型 |
在事件处理程序中,对象this始终等于currentTarget,不一定等于target。
只有在事件处理程序执行中,event对象才存在。一旦程序执行完毕,将会被立即销毁。
3.2 IE中的事件对象
属性/方法 | 类型 | 读/写 | 说明 |
---|---|---|---|
cancelBubble | Boolean | 读写 | 默认为false。用于取消事件冒泡,与DOM中的stopPropagation()相同 |
returnValue | Boolean | 读写 | 默认为true,用于取消默认行为,与DOM中的preventDeafault()相同 |
srcElement | Element | 只读 | 事件目标元素,与DOM中的target相同 |
type | String | 只读 | 被触发的事件类型 |
3.3 跨浏览器的事件对象
var eventUtil = {
addHandler: function(ele, type, handler) {
// 代码在上文,
},
getEvent: function(event) {
return event || window.event;
},
getTarget: function(event) {
// 该语句可以不用,关键是传入的event是否已经被处理
// var event = event || window.event;
return event.target || event.srcElement;
},
preventDefault: function(event) {
if(event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
removeHandler: function(ele, type, handler) {
// 省略代码
},
stopPropagation: function(event) {
if(event.stopPropagation) {
event.stopPropagation(();
} else {
event.cancelBubble = true;
}
},
};
4.1 UI事件
事件 | 说明 |
---|---|
load | 页面完全加载后触发 |
unload | 页面完全卸载或触发 |
select | 用户选中文本框中的文本的时候触发 |
resize | 窗口或框架大小变化的时候触发 |
scroll | 滚动带滚动条的内容时触发 |
4.2 焦点事件
焦点事件会在页面获得或者失去焦点的时候触发。利用这些事件和 document.hasFocus()方法及document.activeElement属性配合,可以定位用户在页面上的行踪。
方法/属性 | 说明 |
---|---|
blur | 失去焦点时触发,不会冒泡 |
DOMFocusOut | 失去焦点时触发,是blur的通用版本,只有opera支持,DOM废弃 |
focusOut | 失去焦点触发,冒泡, |
focus | 获得焦点触发。不会冒泡 |
DOMFocusIn | 获得焦点触发,冒泡,只要opera支持,DOM3废弃 |
focusIn | 获得焦点触发。 |
注意:判断浏览器是否支持某些事件
var isSupported = document.implementation.hasFeature("FoucusEvent", "3.0");
4.3 鼠标和滚轮事件
DOM3中定义了以下9个鼠标事件
事件 | 说明 |
---|---|
click | 单击或回车时触发 |
dbclick | 双击鼠标触发 |
mousedown | 鼠标按下时触发 |
mouseenter | 鼠标首次进入元素范围触发,且在其后代元素上不会触发 |
mouseleave | 鼠标离开元素范围触发,与mouseenter相对 |
mousemove | 鼠标在元素范围内移动,就会不断触发 |
mouseover | 鼠标进入元素范围内触发, |
mouseout | 鼠标离开元素范围进入另一个元素范围或后代元素范围触发, |
滚轮事件:mousewheel。在火狐下是DOMMouseScroll事件。
属性 | 说明 |
---|---|
screenX | 相对于屏幕坐标的位置 |
screenY | 相对于屏幕位置的Y坐标 |
pageX | 相对于页面的x坐标,ie下无pageX属性,但是有X属性。 |
pageY | 相对于页面的y坐标,ie下无pageY属性,但是有Y属性。 |
clientX | 相对于浏览器视口的x坐标 |
clientY | 相对于浏览器视口位置的y坐标 |
function getCol(event) {
var x = event.pageX? eventPageX: event.x;
}
修改键
属性 | 说明 |
---|---|
shiftkey | 检测是否按下了shift键 |
ctrlkey | 检测是否按下了ctrl键 |
metakey | 检测是否按下了meta键 |
altkey | 检测是否按下了alt键 |
相关元素:
mouseout以及mouseover事件中,有元素得到光标,就一定有元素失去光标。对于mouseout来说,失去光标的是主元素,得到光标的则是相关元素。mouseover则正好相反。
var eventUtil = {
// 省略以上代码
getRelatedTarget: function (event) {
if(event.relatedTarget) {
return event,relatedTarget;
} else if(event.toElement) {
// for ie mouseout event
return event.toElement;
} else if(event.fromElement) {
// for ie mouseover event
return event.fromElement;
} else {
return null;
}
}
// 省略以上代码
}
鼠标按钮
DOM下button属性有三个值:0表示主鼠标按钮,1
表示滚轮按钮,2表示次鼠标按钮。
在ie下,button属性的值有8个,在进行跨浏览器方法的时候,检测到时ie,则需要对button进行规范化。
var eventUtil = {
// 省略已有代码
getButton: function(event) {
if(document.implementation.hasFeature("MouseEvents", "2.0")) {
// DOM
return event.button;
} else {
// ie
switch (event.button) {
case 0:
case 1:
case 3:
case 5:
case 7:
return 0;
case 2:
case 6:
return 2;
case 4:
return 1;
}
}
}
}
鼠标滚轮事件
IE下: mousewheel事件,wheelDelta属性表示鼠标滚动方向,是120的倍数。向上表示+120,向下表示-120。
FF下:DOMMouseScroll事件,detail属性。向上表示-3,向下表示+3。
var eventUtil = {
getWheelDelta: function(event) {
if(event.mousewheel){
return (client.engine.opera && client.engine.opera < 9.5)? -wheelDelta:wheelDelta;
//在opera9.5之前,wheelDelta方向与现在相反,需要做一些处理
} else {
// for ff
return -event.detail*40;
}
}
}
键码
var eventUtil = {
getCharCode: function(event) {
if(typeof event.charCode == 'number') {
return event.charCode;
} else {
// IE8及以前,早期opera在keyCode中保存键码
return event.keyCode;
}
}
}
textInput事件
在DOM3级事件中引入。与keyPress不同,只有在可编辑区域内输入字符的时候触发。后者在任何可获得焦点的元素上都能触发。
4.5 复合事件
4.6 变动事件
在DOM中的某一部分发生改变的时候给出提示。
事件 | 说明 |
---|---|
DOMSubtreeModified | DOM结构中发生任何变化都会被触发 |
DOMNodeInserted | 一个节点被插入的时候触发 |
DOMNodeRemoved | 节点被移除的时候触发 |
DOMNodeInsertedIntoDocument | 节点被直接插入文档,或通过子树间接插入文档的时候触发。在DOMNodeInserted之后触发 |
DOMNodeRemovedFromDocument | 节点被直接从文档中移除,或通过子树被移除的时候触发,在DOMNodeRemoved之后被触发 |
DOMAttrModified | 在特性被修改之后触发 |
DOMCharacterDataModified | 在文本节点的值发生变化的时候触发 |
注:event.relatedNode保存着相关节点。可以类比relatedTarget.
4.7 HTML5事件
5.1 事件委托
通过在祖先元素节点上绑定事件,每次捕获目标元素进行相应的事件处理。1. 当需要绑定的节点非常多的时候,可以采用该方法。节约内存,提升性能。 2. 对于经常动态插入节点的场景,使用事件委托,代替针对每个插入的节点进行事件绑定
"test">
- 1
- 2
...
- N
// 我们不可能对N个li元素都进行事件绑定,尤其是在N很大的情况下。
// 事件委托 简单的例子
var oUl = document.getElementById('test');
eventUtil.addHandler('click', oUl, function(event) {
var target = eventUtil.getTarget(event);//目标元素
// 被点击的li背景色立即变红
target.style.backgroundColor = 'red';
})
5.2 移除事件处理程序
在网页中,过时不用的事件处理程序是影响性能的一个重要原因。
当直接移除带有事件处理函数的元素的时候,造成事件处理函数保持引用,无法被回收。
在进行元素移除的时候,首先对事件处理程序进行手工移除。 例如 : btn.onclick = null;
当进行页面卸载的时候,如果在事件处理程序没有被清理干净之前卸载完成,事件处理程序就会滞留在内存中,每次加载完在卸载页面的时候,滞留的对象就会增加。
在进行页面卸载之前,先通过onunload移除所有事件处理程序。
6.1 DOM中的事件模拟
通过document.createEvent()创建事件。在DOM2级中,所有事件使用英文复数,DOM3级中,使用单数。
HTMLEvents
// 创建事件对象
var event = document.createEvent("MouseEvents");
// 初始化事件对象
event.initMouseEvent("click", true, true, document.defaultView, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
// 触发事件
btn.dispatchEvent(event);
// DOM2级不包含键盘事件,所以使用DOM3级,在使用之前进行检查是否支持该事件
if(document.implementation.hasFeature('KeyboardEvents', '3.0')) {
var event = document.createEvent('KeyboardEvents');
// 初始化事件
event.initKeyboardEvent('keydown', true, true, document.defaultView, 'a', 0, 'Shift', 0);
// 触发事件
textbox.dispatchEvent(event);
}
// 以上模仿的是,按下A同时按下shift键。
注: 以上代码虽然能够模拟键盘事件的触发,却无法向文本域输入任何字符。这是因为无法精确模拟键盘事件
var event = document.createEventObject(); // 不接收参数
// 初始化事件对象,必须手工添加属性
event.altKey = false;
event.ctrlKey = false;
event.keyCode = 65;
// 对添加的属性没有任何限制,即使添加的属性不支持也不所谓。
// 触发事件
textbox.fireEvent('onkeypress', event)