一、事件流
理解事件冒泡(event bubbling)和事件捕获(event capturing),这个不难。
“DOM2级事件” 规定的事件流包括:事件捕获阶段、处于目标阶段和事件冒泡阶段。事件将从document传到目标元素的前一个(事件捕获阶段)元素,然后到达目标元素(处于目标阶段),目标元素的句柄开始执行时,就冒泡(事件冒泡阶段);
二、事件处理程序/侦听器/listener
1.HTML事件处理程序
顾名思义就是写在html文档上的handler。比如:
<input type="button" value="点我" onclick="alert("clicked")"></input> //示例1
要知道这种方式现在因为结构样式功能分离、存在“时差”、难以管理的原因已经很少被使用了,但还是要好好理解一下:某种元素支持的每种事件,都可以使用一个与相应事件处理程序同名的 HTML特性来制定。这里是onclick特性。
要知道“DOM0级事件”中使用“on” 加 “事件名”来确定相应事件的句柄,下面就是将一个匿名函数指定给click事件的句柄。
var oBtn = document.getElementById('btn');
oBtn.onclick = function(){
//body...
}
接着深入理解一下那这句简单的 οnclick="alert("username.value"),
<form method="post">
<input type="text" name="username" value="">
<input type="button" value="Echo username" onclick="alert(username.value)">
</form>
相当于下面这个函数,使用with扩展了作用域,使得它这个局部函数得以访问页面中其他位置的元素,所以它可以在alert里面直接引用username元素。
function(){
with(document){
with(this.form){
with(this){
//body..
}
}
}
}
2.DOM0级事件处理程序
3.DOM2级事件处理程序
addEventListener(type, handler, t/f); removeEventListener(type, handler, t/f)
4.IE事件处理程序
attachEvent("on" + type, handler);detachEvent("on" + type, handler);
三、事件对象(event)
var event = event || window.event;
像实现什么拖拽效果、碰撞检测和做什么小游戏之类的很多东西都需要这个对象。更详细的看书,兼容的看下面。
//JavaScript Document
//兼容事件在IE和标准中的差异
var EventUtil = {
//为事件添加侦听器,主要兼容标准IE、DOM0、DOM2
addHandler: function(element, type, handler) {
if(element.addEventListener){
element.addEvenListener(type, handler, false); //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;
}
},
//阻止默认行为
preventDefault: function(event) {
if (event.preventDefault) {
event.preventDefault();
} else {
event.returnValue = false;
}
},
//阻止冒泡
stopPropagation: function(event) {
if (event.stopPropagation) {
event.stopPropagation();
} else {
event.cancleBubble = true;
}
},
//鼠标事件中按了哪些键;IE和标准虽然使用相同的属性但是属性值不一样,这里按标准
getButton: function(event) {
if (document.implementation.hasFeature("MouseEvents", "2.0")) {
return event.button;
} else {
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;
}
}
},
//获得键盘事件中按下的是哪些键
getCharCode: function(event) {
if (typeof event.charCode == "number") {
return event.charCode;
} else {
return event.keyCode;
}
},
getEvent: function(event){
return event ? event : window.event;
},
getTarget: function(event) {
return event.target || event.srcElement;
},
getRelatedTarget: function(event) {
if (event.relatedTarget) {
return event.relatedTarget;
} else if (event.toElement){
return event.toElement;
} else if (event.fromElement){
return event.fromElement;
}else {
return null;
}
},
getWheelDelta: function(event) {
if (event.wheelDelta){
return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDelta); //这是另一个文件中return出来的判断客户端的对象
}else {
return -event.detail * 40; //针对Firefox的实现差异进行兼容
}
},
getClipboardText: function(event) {
var clipboardData = event.clipboardData || window.clipboardData;
return clipboardData.getData("text");
},
setClipboardText: function(event, value) {
if(event.clipboardData){
event.clipboardData.setData("text/plain", value);
}else if (window.clipboardData){
window.clipboardData.setData("text", value);
}
}
}
四、事件类型
1.UI事件:
当用户与页面上的元素交互时触发。(load、unload、abort(用户停止下载过程时,如果嵌入的内容没有加载完,则在<object>元素上面触发)、error、select、resize、scroll)
2.焦点事件:
当元素获得或失去焦点时。(blur、focus、 focusin、focusout。前两者不冒泡,后两者冒)
3.鼠标与滚轮事件
4.键盘与文本事件
keydown和keypress的区别是:前者是按下任意键是触发,而后者是按下键盘上的字符键时触发
keydown和keypress都是在文本框发生变化之前,而唯一一个文本事件textInput是在文本插入文本框之前会触发,用意是在将文本显示给用户之前更容易拦截文本。(按下之后,显示之前)。
与textInput相关的有event.data 和 event.inputMethod
5.复合事件(DOM3级事件,支持不多,用处不大)
IME:Input Method Editor。可以让用户输入在物理键盘上找不到的字符。
1) compositionstart IME的文本复合系统打开时触发
2) compositionupdate 向输入字段插入新字符时触发
3) compositionend 与1)相反
可通过以下检测
var isSupported = document.implementation.hasFeature("CompositonEvent", "3.0");
6.变动事件(mutation)
删除节点的:DOMNodeRemove(将要删除这个节点,会冒泡)---------DOMNodeRemovedFromDocument(不冒泡)--------------DOMSubtreeModified(DOM结构中发生任何变化时,在其他任何事件之后触发)
插入节点:DOMNodeInserted(已经插入到了新的父节点中,所以event.relatedNode包含对这个父节点的引用,会冒泡)----------------DOMNodeInsertedIntoDocument(不冒泡,event对象不包含任何信息)------------------DOMSubtreeModified
7.HTML5事件
contextmenu事件(右键菜单)我们可以通过阻止默认事件的发生来自定义右键菜单
beforeunload事件,我在写博客时草稿箱会自动保存,当我关闭页面想要离开时就会弹出这样一个对话框,让我在页面卸载前可以阻止这个卸载操作,但是我们不能彻底取消这个事件,因为那就意味着用户无法离开这个页面了,所以它把决定权交给我们,弹出一个询问对话框确认我们的下一步操作。应该是这样做:
window.addEventListener('beforeunload', function(event){
var message = '确认放弃此文章\n确认要离开此页?';
event.returnValue = message;
return message;
});
DOMContentLoaded(在形成完整的DOM树之后触发,不理会图像、JavaScript文件、CSS文件或者其它资源是否已经下载完毕。比load快了一步)对于不支持这个事件的浏览器可以使用0毫秒的setTimeOut,可这也没办法完全保证与该事件,只是一个折中的方法。原因就是:在页面下载和构建期间,只有一个JavaScript处理过程,因此这个超时调用会在该过程结束后立即触发。
readystatechange 绑定该事件的对象会有一个属性readyState(uninitialized, loadinng, loaded, interactive, complete)
hashchange hash:URL中“#” 后面的所有字符串,适用于Ajax应用中用来保存状态或者导航信息。(event.oldValue/newValue).
8.设备事件和触摸与手势事件很复杂,将在后面作为独立的一篇文章进行详细阐述。。。
五、内存和性能
尽量使用事件委托(事件冒泡),移除不再需要的句柄来使内存的使用保持在畅通的状态。
这样子就可以节省内存中的两个对象单位。
<ul id="myLink">
<li id="a">a</li>
<li id="b">b</li>
<li id="c">c</li>
</ul>
var oMyList = document.getElementById('myList');
oMyList.onclick = function(event) {
var event = event || window.event;
var target = event.target || event.srcElement;
switch(target.id){
case 'a':
alert("a");
case 'b':
alert("b");
case 'c':
alert("c");
}
}
六、模拟事件
。。。