JavaScript与HTML之间的交互是通过事件实现的。事件,就是文档或浏览器窗口中发生的一些特定的交互瞬间。
1、事件流:描述的是从页面中接收事件的顺序。
IE提出的事件冒泡流:事件开始由最具体的元素接收,然后向上传播到较为不具体的节点。
Nerscape提出的事件捕获流:由最不具体的元素逐渐传播到最具体的节点。
DOM2级事件规定了事件流包括三个阶段:事件捕获阶段、处于目标阶段和事件冒泡阶段。首先发生的是事件捕获,为截获事件提供了机会。然后实际的目标接收到事件。最后一个阶段是冒泡阶段,可以在这个阶段对事件做出响应。
2、事件处理程序:响应事件的函数。名字一般以“on”开头,如onclick、onload、onmouseover... 添加事件处理程序有3种方法:HTML事件处理程序、DOM0级事件处理程序、DOM2级事件处理程序.
HTML事件处理程序:某个元素支持某种事件,都可以使用一个与相应事件处理程序同名的HTML特性来指定。
例如: <input type = "button" value = "Click" onclick = "alert('Click')" /> ,由于这个值是JavaScript,因此不能在其中使用未转义的HTML语法字符,例如&、“”、<、>。若要使用引号,可以这么来用: <input type = "button" value = "Click" onclick = "alert("Click")" />
DOM0级事件处理程序:将一个函数赋值给一个事件处理程序。例如:
1 var btn = document.getElementById("myBtn"); 2 btn.onclick = function(){ 3 alert("Click"); 4 };
同时,也可以删除DOM0级方法指定的事件处理程序,只要设置为null即可: btn.onclick = null; //删除DOM0级事件处理程序
DOM2级事件处理程序:“DOM2级事件”定义了俩个 方法,用于处理指定和删除事件处理程序的操作:addEventListener()和removeEventListener(),接收3个参数:要处理的事件名、作为事件处理程序的函数和一个布尔值,布尔值如果为true,表示在捕获阶段调用事件处理函数;如果是false(默认),在冒泡阶段调用。同时,IE有自己“独特”的事件处理程序去替代这俩个方法:attachEvent()和detachEvent().这样一来,我们就得苦逼的想着如何兼容俩者了,常用的做法如下:
1 var eventUtil={ //type事件不加on! 2 //添加句柄 3 addHandle:function (element,type,handler){ 4 if(element.addEventListener){ 5 element.addEventListener(type,handler,false); 6 }else if(element.attachEvent){ 7 element.attachEvent("on"+type,handler); 8 }else{ 9 element["on"+type].handler; 10 } 11 } 12 //删除句柄---匿名函数不能被移除 13 removeHandle:function (element,type,handler){ 14 if(element.removeEventListener){ 15 element.removeEventListener(type,handler,false); 16 }else if(element.detachEvent){ 17 element.detachEvent("on"+type,handler); 18 }else{ 19 element["on"+type]=null; 20 } 21 } 22 } 23 24 eventUtil.addHandle(oBtn,'click',show); //调用方法
3、事件对象:在触发DOM上的某个事件时,会产生一个事件对象event,这个对象包含着所有与事件有关的信息。包括导致事件的元素、事件的类型以及其他与特定事件相关的信息。
事件对象的获取和属性方面,IE有显得那么“特殊”。因此,我们处处要想着兼容它。有关事件对象和对象属性,常用的兼容方法如下:
1 var eventUtil={ 2 //获取事件对象 3 getEvent : function (event){ 4 return event ? event : window.event; 5 } 6 //获取事件目标 7 getElement : function(event){ //传入获取到的事件对象 8 return event.target || event.srcElement; 9 } 10 //阻止事件冒泡 11 stopPropagation:function(event){ //传入获取到的事件对象 12 if(event.stopPropagation){ 13 event.stopPropagation; 14 }else{ 15 event.cancelBubble=true; 16 } 17 } 18 //阻止默认行为 19 preventDefault:function(event){ //传入获取到的事件对象 20 if(event.preventDefault){ 21 event.preventDefault; 22 }else{ 23 event.returnValue=false; 24 } 25 } 26 }
具体用法:
1 //获取目标对象 2 btn.onclick = function(event) { 3 event = EventUtil.getEvent(event); //获取事件对象 4 var target = EventUtil.getTarget(event); 5 }; 6 7 //取消默认事件 8 var link = document.getElementById("myLink"); 9 link.onclick = function(event) { 10 event = EventUtil.getEvent(event); //获取事件对象 11 EventUtil.preventDefault(event); 12 } 13 14 //取消冒泡 15 var btn = document.getElementById("myBtn"); 16 btn.onclick = function(event){ 17 alert("Clicked"); 18 event = EventUtil.getEvent(event); 19 EventUtil.stopPropagation(event); 20 }; 21 document.body.onclick = function(event){ 22 alert("Body clicked"); //点击btn,这个不会弹出来 23 };
4、事件类型:Web浏览器中可能发生的事情有很多类型,不同的事件类型具有不同的信息。 “DOM3级事件”规定了以下几类属性:
UI(User Interface,用户界面)事件,当用户与页面上的元素交互时触发;
焦点事件,当元素获取或失去焦点时触发;
鼠标事件,当用户通过鼠标在页面上执行操作时触发;
滚轮事件,当使用滚轮(或类似设备)时触发;
文本事件,当在文档中输入文本时触发;
键盘事件,当用户通过键盘在页面上执行操作时触发;
合成事件,当为IME(Input Method Editor,输入法编辑器)输入字符时触发;
变动(mutation)事件,当底层DOM结构发生变化时触发;
变动名称事件,当元素或属性名变动时触发。此类事件已被废弃。
4.1 UI事件:指的是那些不一定与用户操作有关的事件。这些事件在DOM规范出现之前,都是以这种形式存在的,现有的UI事件如下:
load:当页面完全加载后再window上触发。
unload:当页面完全卸载后再window上触发。
error:当发生JavaScript错误时在window上面触发。
select:当用户选择文本框(<input>或<textarea>)中的一或多个字符时触发。即复制开始时触发。
resize:当窗口或框架的大小变化在window或框架上触发。
scroll:但用户滚动条的元素中内容时,在该元素上面触发。<body>元素中包含所加载页面的滚动条。
4.2 焦点事件:焦点事件会在页面元素获得或失去焦点时触发。
blur:在元素失去焦点时触发。这个事件不会冒泡;所有浏览器都支持它。
focus:在元素获得时触发。这个事件不会冒泡;所有浏览器都支持它。
focusout:与blur等价。
focusin:与focus等价,但它冒泡。
DOMFocusIn:在元素获得焦点时触发。这个事件和focus等价,但它冒泡。只有Opera支持,且在DOM3级事件废除了,选择了focusin。
DOMFocusOut:在元素失去焦点时触发。这个事件是blur的通用版本。只有Opera支持。DOM3级事件废除了,选择了focusout。
4.3 鼠标与滚轮事件
click:在用户单击主鼠标按钮或按下回车键时触发。
dblclick:在用户双击主鼠标时触发。
mousedown:在用户按下了任意鼠标按钮时触发。不能通过键盘触发这个事件。
mouseup:在用户释放鼠标按钮时触发。不能通过键盘触发这个事件。
mouseout:在鼠标指针位于一个元素上方,然后用户将其移入另一个元素时触发。又移入的另一个元素可能位于前一个元素的外部,也可能是这个元素的子元素。不能通过键盘事件触发。
mouseover:在鼠标指针位于一个元素外部,然后用户将其首次移入另一个元素边界之内时触发。不能通过键盘事件触发这个事件。
mouseenter:在鼠标光标从元素外部首次移动到元素范围之内触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。DOM3级纳入规范。IE、Firefox 9+和Opera支持。
mouseleave:在位于元素上方的光标移动到元素范围之外时触发。这个事件不冒泡,而且在光标移动到后代元素上不会触发。DOM3级纳入规范。IE、Firefox 9+和Opera支持。
4.3.1 客户区坐标位置
1 var div = document.getElementById("myDiv"); 2 EventUtil.addHandler(div, "click", function(event){ 3 event = EventUtil.getEvent(event); //获取事件对象 4 alert("Client coordinates : " + event.clientX + "," +event,clientY); //相对于浏览器窗口位置 5 });
4.3.2 页面坐标位置
1 var div = document.getElementById("myDiv"); 2 EventUtil.addHandler(div, "click", function(event){ 3 event = EventUtil.getEvent(event); 4 alert("Page coordation: "+event.pageX + "," + event.pageY);//相对文档坐标 5 }
IE8之前不支持,因此要用clientX/Y 和 滚动信息计算出来。这个时候需要document.body(混杂模式)或documentElement(标准模式)中的scrollLeft和scrollTop属性。计算过程如下:
1 var div = document.getElementById("myDiv"); 2 EventUtil.addHandler(div, "click", function(event) { 3 event = EventUtil.getEvent(event); 4 var pageX = event.pageX, 5 pageY = event.pageY; 6 7 if(pageX === undefined){ 8 pageX = event.clientX + (document.body.scrollTop || document.documentElement.scrollLeft); 9 } 10 11 if(pageY === undefined){ 12 pageY = event.clientY + (docuemnt.body.scrollTop || document.documentElement.scrollTop); 13 } 14 15 alert("Page coordinates : " + pageX + "," + pageY); 16 }
4.3.3 屏幕坐标位置
var div = document.getElementById("myDiv"); EventUtil.addHandler(div, "click", function(event){ event = EventUtil.getEvent(event); alert("Screen coordation: "+event.screenX + "," + event.screenY);//相对电脑屏幕坐标 }
4.3.4 修改键
虽热鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也是可以影响到所要采取的操作。这些修改键就是Shift、Ctrl、Alt和Meta(在window键盘中的Window键,在苹果机中的Cmd键),它们经常被用来修改鼠标事件的行为。DOM为此规定了4个属性,表示这些修改键的状态:shiftKey、ctrlKey、altKey和metaKey。这些属性包含的都是布尔值,如果相应的键被按下,则值为true,否则为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否按下了其中的键。下面来举个例子:
1 var div = document.getElementById("myDiv"); 2 EventUtil.addHandler(div, "click", function(event) { 3 event = EventUtil.getEvent(event); 4 var keys = new Array(); 5 6 if(event.shiftKey){ 7 keys.push("shift"); 8 } 9 10 if(event.ctrlKey){ 11 keys.push("ctrl"); 12 } 13 14 if(event.altKey){ 15 keys.push("altKey"); 16 } 17 18 if(event.metaKey){ 19 keys.push("meta"); 20 } 21 22 alert("Keys: " + keys.join(","); 23 });
4.3.5 鼠标滚轮事件
触发鼠标滚轮事件后,生成的事件对象有一个属性叫:wheelDelta,它是一个数值。在不同的浏览器不同的滚动方向有不同的数值,因此,我们还要去兼容它。
1 var eventUtil ={ 2 //获取鼠标滚轮属性值 3 getWheelDelta:function(event) { 4 if(event.wheelDelta) { 5 return (client.engine.opera && client.engine.opera < 9.5 ? -event.wheelDelta : event.wheelDalta); //针对Opera浏览器 6 }else{ 7 return -event.detail * 40; 8 } 9 } 10 }
具体用法:
1 //相关代码放在私有作用域中,从而不会让新定义的函数干扰全局作用域 2 (function(){ 3 function handleMouseWheel(event) { 4 event = EventUtil.getEvent(event); 5 var delta = EventUtil.getWheelDelta(event); 6 alert(delta); 7 } 8 9 EventUtil.addHandler(document, "mousewheel", handleMouseWheel); 10 EventUtil.addHandler(document, "DOMMouseScroll", handleMouseWheel); 11 })();
4.4 键盘和文本事件:用户在使用键盘时会触发键盘事件。
有3个键盘事件,简述如下:
keydown:当用户按下键盘上的任意键时触发,而且如果按住不放的话,会重复触发此事件。
keypress:当用户按下键盘上的字符键时触发,而且如果按住不放的话,会重复触发此事件。
keyup:当用户释放键盘上的键时触发。
只有一个文本事件:textInput。这个事件是对keypress的补充,用意是将文本显示给用户之前更容易拦截文本。在文本插入文本框之前会触发textInput事件。
在用户按了一个字符键时,首先触发keydown事件,然后紧跟着是keypress事件,最后触发keyup事件。其中,keydown和keypress都是在文本框发生变化之前被触发;而keyup事件则是在文本框已经发生变化之后被触发。
4.4.1 键码
在发生keydown和keyup事件时,event对象的keyCode属性中会包含一个代码,与键盘上一个特定的键对应。对数字字母字符键,keyCode属性的值与ASCII码中对应小写字母的编码相同——与Shift状态无关。DOM和IE的event对象都支持keyCode属性。
1 var textbox = document.getElementById("myText"); 2 EventUtil.addHandler(textbox, "keyup", function(event) { 3 event = EventUtil.getEvent(event); 4 alert(event.keyCode); 5 });
4.4.2 字符编码
发生keypress事件意味着按下的键会影响到屏幕中文本的显示。在所有浏览器中,按下能够插入或删除字符的键都会触发keypress事件;按下其他键能否触发此事件因浏览器而异。IE9+、Firefox、Chrome和Safiri的event对象都支持一个charCode属性,这个属性只有发生在keypress事件时才包含值,而且这个值是按下的那个键所代表字符的ASCII编码。此时keyCode通常等于0或者也等于所按键的键码。IE8及之前版本和Opera则是在keyCode中保存字符的ASCII编码。想要以跨浏览器的方式取得字符编码,必须首先检测charCode属性是否可用,如果不可用则使用keyCode,如下:
1 var eventUtil = { 2 //省略其他代码 3 getCharCode: function(event) { 4 if(typeof event.charCode == "number"){ //判断是否支持charCode属性 5 return event.charCode; 6 }else{ 7 return event.keyCode; 8 }, 9 };
具体用法:
1 var textbox = document.getElementById("myText"); 2 eventUtil.addHandler(textbox, "keypress", function(event) { 3 event = EventUtil.getEvent(event); 4 alert(EventUtil.getCharCode(event)); //将其转化为实际的字符 5 });
附:有关键盘事件和键盘事件对象属性请参考——JS之keyCode、charCode、which对比.
4.4.3 textInput事件
“DOM3级事件”规范中引入了一个新事件,名叫textInput。根据规范,当用户在可编辑区域中输入字符时,就会触发这个事件。这个用于替代keypress的textInput事件的行为稍有不同。区别之一就是任何可以获得焦点的元素都可以触发keypress事件,但只有可编辑区域才能触发textInput事件。区别之二是textInput事件只会在用户按下能够输入实际字符的键时才会被触发,而keypress事件则在按下那些能够影响文本显示的键时也会触发(例如退格键)。该事件对象还有一个属性叫data。这个属性的值就是输入的字符本身的值。先触发该事件,才能显示该字符。
事件部分到此还未结束,暂且列举一些常用的。由于浏览器的兼容性不好,这里就先不多少那些不常用的事件。文章还未结束,后续更精彩...