事件
事件类型
HTML5事件
DOM规范没有涵盖所有浏览器支持的所有事件。很多浏览器还实现了一些自定义的事件。HTML5详尽列出了浏览器应该支持的所有事件。此处讨论得到浏览器完善支持的事件,其他事件会在其余地方讨论。
可以简单地认为该事件是鼠标右键单击事件 (在Windows中是右键单击,在Mac中是Ctrl+单击,以下默认为Windows)。该事件的名称叫上下文菜单 ,就像我们在桌面右键单击出来包含刷新 的菜单一样。我们在页面上右键单击会出现默认菜单,如果要实现我们的自定义菜单,那我们除了将自己自定义的菜单显示以外,还得通过event.preventDefault() (IE8-中用returnValue = false )取消默认的行为。
<!DOCTYPE html>
<html >
<head >
<title > ContextMenu Event Example</title >
</head >
<body >
<div id ="myDiv" > Right click or Ctrl+click me to get a custom context menu. Click anywhere else to get the default context menu.</div >
<ul id ="myMenu" style ="position:absolute;visibility:hidden;background-color:silver" >
<li > <a href ="http://www.nczonline.net" > Nicholas' site</a > </li >
<li > <a href ="http://www.wrox.com" > Wrox site</a > </li >
<li > <a href ="http://www.yahoo.com" > Yahoo!</a > </li >
</ul >
<script type ="text/javascript" >
window.addEventListener("load" , function (event) {
var div = document.getElementById("myDiv" );
div.addEventListener("contextmenu" , function (event) {
event.preventDefault();
var menu = document.getElementById("myMenu" );
menu.style.left = event.clientX + "px" ;
menu.style.top = event.clientY + "px" ;
menu.style.visibility = "visible" ;
});
document.addEventListener("click" , function (event) {
document.getElementById("myMenu" ).style.visibility = "hidden" ;
});
});
</script >
</body >
</html >
支持contextmenu 事件的浏览器有IE、Firefox、Safari、Chrome和Opera11+。
beforeunload事件
该事件是为了让开发人员有可能在页面卸载 前阻止这一操作。显示的消息会告知用户页面将被卸载,询问用户是否真的要关闭页面。 不同浏览器设置消息有所不同。IE8-下需要为将该消息赋值给event.returnValue ,其余浏览器多数是作为该事件处理程序函数的返回值 。但是我测试下来,没办法改变Chrome的提示信息(查阅资料得知:Chrome从51 版(2016 年 4 月)起取消 onbeforeunload 对话框显示自订讯息功能,理由是防止自订讯息被用于诈骗用途。Edge、Firefox 及 Opera到目前都不支持自订讯息功能 。毛法,不强求咯)。
<!DOCTYPE html>
<html >
<head >
<title > BeforeUnload Event Example</title >
</head >
<body >
<div id ="myDiv" > Try to navigate away from this page.</div >
<script type ="text/javascript" >
var addHandler = function (element, type, handler) {
if (element.addEventListener){
element.addEventListener(type, handler, false );
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type] = handler;
}
};
var getEvent = function (event) {
return event ? event : window.event;
}
addHandler(window, "beforeunload" , function (event) {
event = getEvent(event);
var message = "I'm really going to miss you if you go." ;
event.returnValue = message;
return message;
});
</script >
</body >
</html >
DOMContentLoaded事件
该事件是对前面提到的load 事件的改进,我们知道,load事件 是在页面中的一切都加载完毕时触发(这里只谈页面,虽然元素也有load 事件)。而DOMContentLoaded 事件会在形成完整的DOM树之后就会触发,不理会图像、JavaScript文件、CSS文件或其他资源是否已经下载完毕。该事件意味着用户能够尽早地同页面交互 。 该事件的目标是document ,它会冒泡到window ,所以我们可以为document或window添加相应的事件处理程序。
<!DOCTYPE html>
<html >
<head >
<title > DOMContentLoaded Event Example</title >
</head >
<body >
<div id ="myDiv" > DOMContentLoaded example - works only in Opera and Firefox</div >
<script type ="text/javascript" >
window.addEventListener("DOMContentLoaded" , function (event) {
alert("Content loaded." );
});
window.addEventListener("load" , function (event) {
alert("Window loaded." );
});
</script >
</body >
</html >
对于不支持DOMContentLoaded 事件的浏览器,我们可以用下面代码:
setTimeout(function () {
},0 )
这段代码的意思是在当前JavaScript处理完成后立即运行这个函数 。不过必须作为页面的第一个超时调用。即便如此,由于浏览器差异等等因素,也不能保证该超时调用一定会先于load事件触发(反正我测下来都是后于load事件触发的。)。
readystatechange 事件
IE 为DOM文档中的某些部分提供了readystatechange 事件(话虽这么说,Chrome 后期也实现了这个事件)。这个事件的目的是提供与文档或元素的加载状态有关的信息。支持readystatechange事件的每个对象都有一个readyState 属性(document 也有这个属性),可能包含下列5个值中的一个。
uninitialized (未初始化):对象存在但尚未初始化。loading (正在加载):对象正在加载数据。loaded (加载完毕):对象加载数据完毕。interactive (交互):可以操作对象了,但还没有完全加载。complete (完成):对象已经加载完毕。这些状态看起来很直观,但并非所有对象都会经历readyState 的这几个阶段。换句话说,如果某个阶段不适用某个对象,则该对象完全可能跳过该阶段;并没有规定哪个阶段适用于哪个对象。显然,这意味着readystatechange 事件经常会少于4 次,而readyState 属性的值也不总是连续的。 对于document 而言,值为”interactive “的readyState 会在与DOMContentLoaded 大致相同的时刻触发readystatechange 事件。此时,DOM树已经加载完毕,可以安全地操作它了,因此就会进入交互(interactive )阶段。但与此同时,图像及其他外部文件不一定可用。
<!DOCTYPE html>
<html >
<head >
<title > DOMContentLoaded Event Example</title >
</head >
<body >
<div id ="myDiv" > DOMContentLoaded example - works only in Opera and Firefox</div >
<script type ="text/javascript" >
document.addEventListener("readystatechange" , function (event) {
if (document.readyState == "interactive" ){
alert("Content loaded1" );
}
});
document.addEventListener("DOMContentLoaded" , function (event) {
if (document.readyState == "interactive" ){
alert("Content loaded2" );
}
});
window.addEventListener("load" , function (event) {
alert("load loaded2" );
});
</script >
</body >
</html >
另外, <script>
和<link>
元素也会触发readystatechange 事件,可以用来确定外部的JavaScript 和CSS 文件是否已经加载完成。与在其他浏览器中一样,除非把动态创建的元素添加到页面中, 否则浏览器不会开始下载外部资源。基于元素触发的readystatechange 事件也存在同样的问题, 即readyState 属性无论等于”loaded ” 还是”complete “都可以表示资源已经可用。有时候,readyState 会停在”loaded “阶段而永远不会“完成”;有时候,又会跳过”loaded “阶段而直接“完成”。于是,还需要像对待document 一样采取相同的编码方式。例如,下面展示了一段加载外部JavaScript 文件的代码。 这个事件如此复杂,使用的时候要小心一点,我就不用了。
pageshow 和pagehide 事件
Firefox 和Opera 有一个特性,名叫“往返缓存 ”(back-forward cache,或bfcache ),可以在用户使用浏览器的“后退”和“前进”按钮时加快页面的转换速度。这个缓存中不仅保存着页面数据,还保存了DOM 和JavaScript 的状态;实际上是将整个页面都保存在了内存里。如果页面位于bfcache 中,那么再次打开该页面时就不会触发load 事件(Chrome没有这个特性…)。pageshow 事件会在页面重新加载后,触发load事件 之后触发。如果页面来自bfcache ,则跳过load 事件,直接触发pageshow 事件。虽然pageshow 的目标是document ,但是我们必须得为window 指定事件处理程序。除了通常的属性之外,pageshow 事件的event 对象还包含一个名为persisted 的布尔值属性。如果页面被保存在了bfcache 中,则这个属性的值为true;否则,这个属性的值为false (其实是指该页面是否是从bfcache 中读取的)。 与pageshow 事件对应的是pagehide 事件,该事件会在浏览器卸载页面的时候触发,而且是在unload 事件之前触发。与pageshow 事件一样,pagehide 在document 上面触发,但其事件处理程 序必须要添加到window 对象。这个事件的event 对象也包含persisted 属性,不过其用途稍有不同。如果页面在卸载之后 会被保存在bfcache 中,那么persisted 的值也会被设置为true 。 由于我只有Chrome浏览器(IE就算了),以下是在Chrome中的测试代码(刷新页面,可以看到pagehide下的 event.persisted为false,也就是说不存入bfcache,所以也就没有接着测试了 ):
<!DOCTYPE html>
<html >
<head >
<title > PageShow/PageHide Event Example</title >
</head >
<body >
<script type ="text/javascript" >
(function () {
var showCount = 0 ;
window.addEventListener("load" , function () {
alert("Load fired" );
});
window.addEventListener("pageshow" , function (event) {
showCount++;
alert("Show has been fired " + showCount + " times. Persisted? " + event.persisted);
});
window.addEventListener("pagehide" , function (event) {
console.log("Hiding. Persisted? " + event.persisted);
});
})();
</script >
</body >
</html >
我还是想知道在Firefox里面的效果,忍了十三章还是下了Firefox。不过我找不到合适的例子。
hashchange 事件
HTML5 新增了hashchange 事件,以便在URL 的参数列表(及URL 中“#”号后面的所有字符串)发生变化时通知开发人员。之所以新增这个事件,是因为在Ajax 应用中,开发人员经常要利用URL 参数列表来保存状态或导航信息 。 必须把hashchange 事件处理程序添加给window 对象。event 对象中额外包含两个属性:oldURL 和newURL 。
<!DOCTYPE html>
<html >
<head >
<title > Hash Change Example</title >
<script type ="text/javascript" src ="EventUtil.js" > </script >
</head >
<body >
<p > Click each of these links to change the URL hash.</p >
<ul >
<li > <a href ="#up" > Up</a > </li >
<li > <a href ="#down" > Down</a > </li >
</ul >
<p > This example only works in browsers that <code > onhashchange</code > .</p >
<script type ="text/javascript" >
EventUtil.addHandler(window, "hashchange" , function (event) {
alert("Old URL: " + event.oldURL + "\nNew URL: " + event.newURL);
});
</script >
</body >
</html >
支持hashchange 事件的浏览器有IE8+、Firefox 3.6+、Safari 5+、Chrome 和Opera 10.6+ 。在这些浏览器中,只有Firefox 6+、Chrome 和Opera 支持oldURL 和newURL 属性(此时就可以用到之前学过的location对象中的hash属性了 )。
设备事件
智能手机 和平板电脑 的普及,为用户与浏览器交互引入了一种新的方式,而一类新事件也应运而生。
orientationchange事件
苹果公司为移动Safari 中添加了orientationchange 事件,以便开发人员能够确定用户何时将设备由横向查看模式 切换为纵向查看模式 。移动Safari 的window.orientation 属性中可能包含3 个值:0 表示肖像模式,90 表示向左旋转的横向模式(“主屏幕”按钮在右侧),-90 表示向右旋转的横向模式(“主屏幕”按钮在左侧)。相关文档中还提到一个值,即180 表示iPhone 头朝下;但这种模式至今尚未得到支持。 所有iOS 设备都支持orientationchange 事件和window.orientation 属性。
MozOrientation事件
这个事件和orientationchange 事件差不多,是在window 对象上触发的,event 对象包含三个属性:x、y 和z。这几个属性的值都介于1 到-1 之间,表示不同坐标轴上的方向。在静止状态下,x 值为0,y 值为0,z 值为1(表示设备处于竖直状态)。**如果设备向右倾斜,x 值会减小;反之,向左倾斜,x 值会增大。类似地,如果设备向远离用户的方向倾斜,y 值会减 小,向接近用户的方向倾斜,y 值会增大。z 轴检测垂直加速度度,1 表示静止不动,在设备移动时值会减小。(失重状态下值为0。)**
deviceorientation和devicemotion事件
这两个事件都是关于手机在各个方向上的移动 和角度加速度之类的,有兴趣的可以看书p395 。
触摸与手势事件
触摸事件
有以下几个触摸事件:
touchstart :当手指触摸屏幕时触发;即使已经有一个手指放在了屏幕上也会触发。touchmove :当手指在屏幕上滑动时连续地触发。在这个事件发生期间,调用preventDefault() 可以阻止滚动。touchend :当手指从屏幕上移开时触发。touchcancel :当系统停止跟踪触摸时触发。关于此事件的确切触发时间,文档中没有明确说明。 上述几个事件都会冒泡,都可以取消。每个触摸事件的event 对象都提供了在鼠标事件中常见的属性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey 。 除了常见的DOM属性外,触摸事件还包含下列三个用于跟踪触摸的属性:
touches :表示当前跟踪的触摸操作的Touch 对象的数组。targetTouchs :特定于事件目标的Touch 对象的数组。changeTouches :表示自上次触摸以来发生了什么改变的Touch 对象的数组。 每个Touch 对象包含下列属性:
clientX:触摸目标在视口中的x 坐标。 clientY:触摸目标在视口中的y 坐标。 identifier:标识触摸的唯一ID。 pageX:触摸目标在页面中的x 坐标。 pageY:触摸目标在页面中的y 坐标。 screenX:触摸目标在屏幕中的x 坐标。 screenY:触摸目标在屏幕中的y 坐标。 target:触摸的DOM 节点目标。 由于我电脑没有发wifi的功能,我手机也连不上我的电脑,所以这些都没法测试了。以下是测试代码:
<!DOCTYPE html>
<html >
<head >
<title > Touch Events Example</title >
<meta name ="viewport" content ="width=device-width, user-scalable=no" >
</head >
<body >
<p > Touch anywhere on the screen. This only works on an iPhone or iPod Touch running iPhone 2.x software.</p >
<div id ="output" >
</div >
<script type ="text/javascript" >
function handleTouchEvent (event) {
if (event.touches.length == 1 ){
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 + ")" ;
break ;
}
}
}
document.addEventListener("touchstart" , handleTouchEvent, false );
document.addEventListener("touchend" , handleTouchEvent, false );
document.addEventListener("touchmove" , handleTouchEvent, false );
</script >
</body >
</html >
手势事件
有三个手势事件,分别介绍如下:
gesturestart:当一个手指已经按在屏幕上而另一个手指又触摸屏幕时触发。 gesturechange:当触摸屏幕的任何一个手指的位置发生变化时触发。 gestureend:当任何一个手指从屏幕上面移开时触发。 触摸事件和手势事件之间存在某种关系。当一个手指放在屏幕上时,会触发touchstart 事件。如果另一个手指又放在了屏幕上,则会先触发gesturestart 事件,随后触发基于该手指的touchstart 事件。如果一个或两个手指在屏幕上滑动,将会触发gesturechange 事件。但只要有一个手指移开,就会触发gestureend 事件,紧接着又会触发基于该手指的touchend 事件。 与触摸事件一样,每个手势事件的event 对象都包含着标准的鼠标事件属性:bubbles、cancelable、view、clientX、clientY、screenX、screenY、detail、altKey、shiftKey、ctrlKey 和metaKey。 此外,还包含两个额外的属性:rotation 和scale 。其中,rotation 属性表示手指变化引起的旋转角度 ,负值表示逆时针旋转,正值表示顺时针旋转(该值从0 开始)。而scale 属性表示两个手指间距离的变化情况(例如向内收缩会缩短距离);这个值从1 开始,并随距离拉大而增长,随距离缩短而减小。
小结
这篇文章内容多数枯燥(用的少),所以copy居多。