一、事件流 理解事件冒泡(event bubbling)和事件捕获(event capturing),这个不难。 “DOM2级事件” 规定的事件流包括:事件捕获阶段、处于目标阶段和事件冒泡阶段
一、事件流
理解事件冒泡(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...}
接着深入理解一下那这句简单的 onclick="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"); }}
六、模拟事件
。。。