JS事件类型--1
滚轮事件其实就是一个mousewheel事件,这个事件跟踪鼠标滚轮,类似Mac的触屏版。
一、客户区坐标位置
鼠标事件都是在浏览器视口的特定位置上发生的。这个位置信息保存在事件对象的clientX和clientY属性中。所有浏览器都支持者两个属性。clientX和clientY表示事件发生时鼠标指针在视口中的水平和垂直坐标。
document.addEventListener('click',function(event){ document.title=event.clientX+' , '+event.clientY; },false);
给document指定了onclick事件处理程序,单击页面时在title中可以看到客户端的坐标信息。
注意:这些值中不包括页面滚动的距离,因为这个位置并不表示鼠标在页面上的位置。
二、页面坐标位置
通过clientX和clientY能够指定鼠标是在视口中声明位置发生的,而页面坐标通过事件对象的pageX和pageY属性,能够得到事件是在页面中的什么位置发生的。即pageX和pageY表示鼠标光标在页面中的位置,因此坐标是从页面本身而非视口的左边和顶边计算的。
document.addEventListener('click',function(event){ console.log(event.clientX+' , '+event.clientY); console.log(event.pageX+' , '+event.pageY); },false);
在页面没有滚动的情况下,pageX和pageY的值与clientX和clientY的值相等。
IE8及更早版本不支持事件对象上的页面坐标,不过使用客户区坐标和滚动信息可以计算出来。这时候需要用到document.body(混杂模式)或document.documentElement(标准模式)中的scrollLeft和scrollTop属性。如下:
<script type="text/javascript"> var div=document.getElementById("myDiv"); EventUtil.addHandler(div,"click",function(event){ event=EventUtil.getEvent(event); var pageX=event.pageX, pageY=event.pageY; if(pageX==undefined) { pageX=event.clientX+(document.body.scrollLeft || document.documentElement.scrollLeft); } if(pageY==undefined){ pageY=event.clientY+(document.body.scrollTop || document.documentElement.scrollTop); } alert("Page coordinates:" +pageX+" , "+pageY); }); </script>
三、屏幕坐标位置
鼠标事件发生时,不仅会有相对于浏览器窗口的位置,还有一个相对于整个电脑屏幕的位置。而通过screenX和screenY属性就可以确定鼠标事件发生时鼠标指针相对于整个屏幕的坐标信息。
document.addEventListener('click',function(event){ console.log("Client coordinates"+event.clientX+' , '+event.clientY); console.log("Page coordinates "+event.pageX+' , '+event.pageY); console.log("Screen coordinates "+event.screenX+' , '+event.screenY); },false);
四、修改键
虽然鼠标事件主要是使用鼠标来触发的,但在按下鼠标时键盘上的某些键的状态也可以影响到所要采取的操作。这些修改键就是Shift、Ctrl、Alt和Meta(在Windows键盘中是Windows键,在苹果机中是Cmd键) ,它们通常被用来修改鼠标事件的行为。
DOM为此规定了4个属性,表示这些修改键的状态:shiftKey,ctrlKey,altKey和metaKey。这些属性中包含的都是布尔值,如果相应的键被按下了,则值为true,否则值为false。当某个鼠标事件发生时,通过检测这几个属性就可以确定用户是否同时按下了其中的键。如下:
<script type="text/javascript"> var div=document.getElementById("myDiv"); EventUtil.addHandler(div,"click",function(event){ event=EventUtil.getEvent(event); var keys=new Array(); if(event.shiftKey){ keys.push("shift");; } if(event.ctrlKey){ keys.push("ctrl"); } if(event.altKey){ keys.push("alt"); } if(event.metaKey){ keys.push("meta"); } alert("Keys: "+keys.join(",")); }); </script>
通过一个onclick事件处理程序检测了不同修改键的状态。数组keys中包含着被按下的修改键的名称。也就是说,如果有属性值为true,就会将对应修改键的名称添加到keys数组中。在事件处理程序的最后,有一个警告框将检测到的键的信息显示给用户。
Note:IE8及之前的版本不支持metaKey属性,IE9、Firefox、Safari、Chrome和Opera都支持这4个键。
五、相关元素
在发生mouseover和mouseout事件时,还会涉及更多的元素。这两个事件都会涉及把鼠标指针从一个元素的边界之内移动到另一个元素的边界之内。
对mouseover事件而言,事件的主目标是获得光标的元素,而相关元素就是那个失去光标的元素。
类似地,对mouseout事件而言,事件的主目标是失去光标的元素,而相关元素是获得光标的元素。
DOM通过event对象的relatedTarget属性获得相关元素的信息。relatedTarget属性只对mouseover和mouseout事件才包含值;对于其他事件,这个属性值是null。
IE8及之前版本不支持relatedTarget属性,但提供了保存着相同信息的不同属性。
在mouseover事件触发时,IE的fromElement属性中保存了相关元素;
在mouseout事件触发时,IE的toElement属性保存了相关元素;(IE9支持relatedTarget,fromElement,toElement都支持)
例子:
<div id="myDiv" style="height: 100px;width: 100px;"></div>
var div=document.getElementById("myDiv"); EventUtil.addHandler(div,"mouseout",function(event){ event=EventUtil.getEvent(event); var target=EventUtil.getTarget(event); var relatedTarget=EventUtil.getRelatedTarget(event); alert("Moused out of "+target.nodeName+" to "+relatedTarget.tagName); });
六、鼠标按钮
对于mousedown和mouseup事件,在event对象中存在一个button属性,表示按下或释放的按钮。
DOM的button属性有3个取值:
- 0:表示主鼠标按钮(鼠标左键)
- 1:表示中间的鼠标按钮(鼠标滚轮按钮)
- 2:表示次鼠标按钮(鼠标右键)
IE8及之前版本也提供了button属性,但这个属性的值与DOM的button属性有很大差异。
- 0:表示没有按按钮。——》0
- 1:表示按下了鼠标左键——》0
- 2:表示按下了鼠标右键——》2
- 3:表示同时按下了鼠标左右键——》0
- 4:表示按下了中间的鼠标按钮——》1
- 5:表示同时按下了鼠标左键和中间的鼠标按钮——》0
- 6:表示同时按下了鼠标右键和中间的鼠标按钮——》2
- 7:表示同时按下了三个鼠标按钮——》》DOM0
DOM模型下的button属性比IE模型下的button属性更简单实用,因为同时按下多个鼠标按钮的情形十分罕见。
最常见的的做法就是将IE模型规范化为DOM方式,毕竟除IE8及更早版本之外都支持DOM模型。
将IE中其他选项分别转换成如同按下这三个按键中的一个即可(同时将主按钮作为优先选取的对象)。
IE中返回的5和7会被转换成DOM模型中的0。
重点:由于单独使用能力检测无法确定差异(两种模型有同名的button属性) ,因此必须另辟蹊径。支持DOM版鼠标事件的浏览器可以通过hasFeature()方法来检测,所以跨浏览器的getButton()方法如下:
getButton:function(event){ if(document.implementation.hasFeature("MouseEvents","2.0")){ return event.button; }else{ switch(event.buton){ case 0: case 1: case 3: case 5: case 7: return 0; case 2: case 6: return 2; case 4: return 1; } } }
document.implementation.hasFeature("MouseEvents","2.0"))通过检测"MouseEvents"这个特性,就可以确定event对象中存在的button属性中是否包含正确的值。
Note:在onmouseup事件处理程序时,button值表示释放的是哪个按钮。此外,如果不是按下或释放了主鼠标按钮,Opera不会触发mouseup或mousedown事件。
七、更多的事件信息
“DOM2级事件”规范在event对象中还提供了detail属性,用于给出有关事件的更多信息。对于鼠标事件来说,detail中包含了一个数值,表示在给定位置上发生了多少次单击。
在同一个像素上相继地发生一次mousedown和一次mouseup事件算作一次单击。detail属性从1开始计数,每次单击递增。如果鼠标在mousedown和mouseup之间移动了位置,则detail会被重置为0。
八、鼠标滚轮事件
当用户通过是不滚轮与页面交互,在垂直方向上滚动页面时(无论向上还是向下),就会触发mousewheel事件。由于mousewheel事件非常流行,而且所有浏览器都支持它,所以HTML5也加入了mousewheel事件。
mousewheel事件可以在任何元素上面触发,最终会冒泡到document(IE8)或者window(IE9,Opera,Chrome及Safari)对象。
相关属性:除了鼠标事件的所有标准信息外,mousewheel事件对应的event对象还包含一特殊的wheelDelta属性。
当用户向前滚动鼠标滚轮时,wheelDelta是120的倍数;当用户向后滚动鼠标滚轮时,wheelDelta是-120的倍数。
多数情况,只需要知道鼠标滚轮滚动的方向即可,这通过wheelDelta的正负号实现。
兼容性:
Opera 9.5之前的版本,wheelDelta值的正负号是颠倒的。
Firefox支持一个DOMMouseScroll的类似事件,也是在鼠标滚轮轮滚动时触发。鼠标有关信息保存在detail属性中。当向前滚动鼠标滚轮时,这个属性的值是-3的倍数,向后滚动鼠标滚轮时,这个值是3的倍数。
以下为兼容性处理。
getWheelDelta:function(event){ if(event.wheelDelta){ return(client.engine.opera && client.engine.opera<9.5? -event.wheelDelta:event.wheelDelta); }else{ return -event.detail*40; } }
九、触摸设备
iPhone和iPad没有鼠标。
- 不支持dblclick事件。双击浏览器窗口会放大画面,而且没有办法改变该行为。
- 轻击可单击元素会触发mousemove事件。如果此操作会导致内容变化,将不再有其他事件发生;如果屏幕没有因此变化,那么会依次触发mousedown,mouseup和click事件。轻击不可单击元素不会触发任何事件。可单击的元素是指那些可以单击产生默认操作的元素(如链接),或者那些已经被指定了onclik事件处理程序的元素。
- mousemove事件也会触发mouseover和mouseout事件。
两个手指放在屏幕上且页面随手指移动而滚动时会触发mousewheel和scroll事件。
十、触摸事件
- touchstart:当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。
- touchmove:当手指在屏幕上滑动时连续地触发。在这个世界发生期间,调用preventDefault()可以阻止滚动。
- touchend:当手指在屏幕上移开时触发。
- touchcancel:当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。
上面这几个事件都会冒泡,也都可以取消。虽然这些触摸事件没有在DOM规范中定义,但它们却是以兼容DOM的方式实现的。因此,每个触摸事件的event对象都提供了鼠标事件中常见的属性:bubbles,cancelable,view,clientX,clientY,screenX,screenY,detail,altKey,shiftKey,ctrlKey和metaKey。
除了常见的DOM属性外,触摸世界还包含下列三个用于跟踪触摸的属性。
- touches:表示当前跟踪的触摸操作的Touch对象的数组。
- targetTouches:特定于事件目标的Touch对象的数组。
- changedTouches:表示字上次触摸以来发生了什么改变的Touch对象的数组。
每个Touch对象包含下列属性:
- clientX:触摸目标在视口中的x坐标。
- clientY:触摸目标在视口中的y坐标。
- identifier:标识触摸的唯一ID。
- pageX:触摸目标在页面中的x坐标。
- pageY:触摸目标在页面中的y坐标。
- screenX:触摸目标在屏幕中的x坐标。
- screenY:触摸目标在屏幕中的y坐标。
- target:触摸的DOM节点目标。
使用这些属性可以跟踪用户对屏幕的触摸操作。
<div id="output"></div>
function handlerTouchEvent(event){ //只跟踪一次触摸 if(event.touches.length==1 || event.touches.length==0){//书上这里有错 var output=document.getElementById("output"); switch(event.type){ case "touchstart": output.innerHTML="Touch started ( "+event.touches[0].clientX+", "+event.touches[0].clientY+")"; break; case "touchend": output.innerHTML+="<br/>Touch ended ("+event.changedTouches[0].clientX+", "+event.changedTouches[0].clientY+")"; break; case "touchmove": event.preventDefault(); //阻止滚动 output.innerHTML+="<br/>Touch moved ("+event.changedTouches[0].clientX+", "+event.changedTouches[0].clientY+")"; } } } EventUtil.addHandler(document,"touchstart",handlerTouchEvent); EventUtil.addHandler(document,"touchend",handlerTouchEvent); EventUtil.addHandler(document,"touchmove",handlerTouchEvent);
以上代码会跟踪屏幕上发生的一次触摸操作。为简单起见,只会在有一次活动触摸操作的情况下输出信息。
当touchstart事件发生时,会将触摸的位置信息输出到<div>元素中。
当touchmove事件发生时,会取消其默认行为,阻止滚动(触摸移动的默认行为是滚动页面),然后输出触摸操作的变化信息。
而touched事件则会输出有关触摸操作的最终信息。
注意:在touched事件发生时,touches集合中就没有任何Touch对象了,因为不存在活动的触摸操作;此时,就必须转而使用changedTouches集合。
/*当触发touchstart和touchmove事件的时候没有问题,程序能正确的进入 if 然后根据case执行对应的语句,但是当触发touchend事件的时候,event.touches.length已经等于0了,不能再进入if 中,也就不能执行case中的语句,所以触发touchend的时候永远不会执行程序。所以判断条件要加上 event.touches.length==0.*/
这些事件会在文档的所有元素上面触发,因而可以分别操作页面的不同部分。在触摸屏幕上的元素时,这些事件(包括鼠标事件) 发生的顺序如下:
- touchstart
- mouseover
- mousemove(一次)
- mousedown
- mouseup
- click
- touched
桌面版Firefox 6+和Chrome也支持触摸事件。
十一、手势事件
当两个手指触摸屏幕时就会产生手势,手势通常会改变显示项的大小,或者旋转显示项。有三个手势事件,如下:
- gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。
- gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。
- gestureend:当任何一个手指从屏幕上移开时触发。
只有两个手指都触摸到事件的接收容器时才会触发这些事件。
在一个元素上设置事件处理程序,意味着两个手指必须同时位于该元素的范围之内,才能触发手势事件(这个元素就是目标)。
由于这些事件冒泡,所以讲事件处理程序放在文档上也可以处理所有手势事件。
此时,事件的目标就算两个手指都位于其范围内的那个元素。
触摸事件和手势事件关系:
每个手势事件的event对象都包含着标准的鼠标事件属性:bubbles,cancelable,view,clientX,clientY,screenX,screenY,detail,altKey,shiftKey,ctrlKey和metaKey。此外还有两个额外的属性:rotation和scale。
- rotation属性:表示手指变化引起的旋转角度,负值表示逆时针旋转,正值表示顺时针旋转(该值从0开始)。
- scale属性:表示两个手指间距离的变化情况(例如向内收缩会缩短距离);这个值从1开始,并随距离拉大而增长,随距离缩短而减小。
例子:
function handleGestureEvent(event){ var output=document.getElementById("output"); switch(event.type){ case "gesturestart": output.innerHTML="Gesture started ( "+event.ratation+", scale"+event.scale+")"; break; case "gestureend": output.innerHTML+="<br/>Gesture ended ("+event.rotation+", scale"+event.scale+")"; break; case "gesturechange": event.preventDefault(); //阻止滚动 output.innerHTML+="<br/>Gesture changed ("+event.rotation+",scale "+event.scale+")"; } } EventUtil.addHandler(document,"gesturestart",handleGestureEvent); EventUtil.addHandler(document,"gestureend",handleGestureEvent); EventUtil.addHandler(document,"gesturechange",handleGestureEvent);
扩展阅读:
javaScript事件(四)event的公共成员(属性和方法)