事件在Web应用程序中是有魔力的要素。如果希望Web应用程序应该流畅并且不唐突地响应用户操作,就像是桌面应用程序一样。能够让Web应用程序更具有桌面应用程序的感觉虽然算不上具有革命性,但确实要改变看待问题的方式。事实上,只要多一些独创性和预见性,你就能做到以最小的努力、最低的成本和最少的时间投入,开发出具有桌面应用程序体验的Web应用。不过前提是要理解浏览器如何与人进行交互。
事件就是操作检测与脚本执行的组合,或者基于检测到的操作类型并在某个对象上调用事件侦听器。首先,需要澄清几个术语:
□ 事件:这里需要澄清的是事件并不是以”on”开头的。例如,onclick不是事件,click才是事件。
□ 事件侦听器:当指定的事件发生时会执行的函数或方法。有时也被称为“事件处理程序”,“事件侦听器”是遵循DOM2级事件规范中的术语。
□ 事件注册:为DOM元素的具体事件指定事件侦听器的过程。注册可以通过几种不同的方式来完成。
□ 调用:使用动词“invoke”来描述浏览器在检测到某种操作之后执行相应事件侦听器的情形。类似的术语还可能包括呼叫(called)、激发(fired)、执行(executed)或触发(triggered)等。
事件类型
事件可以分为几种类型:对象事件、鼠标事件、键盘事件、表单事件、W3C事件以及针对浏览器的事件。
对象事件
对象事件既适用于JavaScript对象(例如window对象),也适用于DOM对象(例如HTMLImageElement对象)
1. load和unload事件
浏览器会在完成对页面的载入时调用window的load事件。通过借助于load事件,可以使不唐突的行为增强只有在JavaScript有效时才会应用到页面上。同样地,当用户通过单击链接或者关闭窗口而即将离开当前页面时,会调用window对象的unload事件。因此,可以通过unload事件侦听器在页面被关闭之前捕获最后一瞬间的信息。
2. abort和error事件
与load和unload事件类似,error事件既适用于window对象,也适用于图像对象。error事件在动态载入图像时,可以用来识别图像载入错误。如果创建了一个新的img DOM要素,那么就可以使用load事件侦听器在且只在图像载入成功的情况下再将这个DOM元素添加到文档中。同样,对于载入图像时出现错误的情况,可以使用error事件侦听器来进行说明,并采取适当的行动。
ADS.addEvent(window,'load',function() { // 创建一个图像元素 var image = document.createElement('IMG'); // 载入完毕后添加到文档 ADS.addEvent(image, 'load', function() { document.body.appendChild(image); }); // 如果载入出错,则添加相应的信息 ADS.addEvent(image, 'error' ,function() { var message = document.createTextNode('The image failed to load'); document.body.appendChild(message); }); // 设置src属性 image.setAttribute('src',images/working.jpg');
在图像载入成功的情况下,它会被添加到文档主体中;但如果载入失败,则会看到出错信息。
至于abort事件,它的作用很小。只有在图像完全载入之前,因为浏览器停止载入页面而导致图像载入失败的情况下,才会调用这个事件。而这种情况通常只在单击浏览器“停止”按钮是才会发生。
3. resize事件
当调整浏览器窗口的大小而导致文档的视图发生改变时才会触发resize事件。
4. scroll事件
scroll事件适用于具有overflow:auto样式的元素,并且会在元素滚动期间连续地触发。可能引起事件的操作包括:拖动滚动条、滚动鼠标滚轮、按下键盘的方向键或其他滚动操作。
鼠标移动事件
□ 当鼠标处于移动过程中时,鼠标指针下方的对象就会连续地触发mousemove事件
□ 当指针移动到一个新对象上面时则会触发mouseover事件
□ 当指针移出对象时会触发mouseout事件
示例文件由一个非常简单的HTML文件和相应的JavaScript脚本文件组成,包括完整的自定义ADS库,一个myLogger日志对象,以及load事件侦听文件。
效果演示
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>Mouse Move Events</title> <link rel="stylesheet" type="text/css" href="style.css" /> <script type="text/javascript" src="libs/ADS-final-verbose.js"></script> <script type="text/javascript" src="libs/myLogger-final/myLogger.js"></script> <script type="text/javascript" src="move.js"></script> </head> <body> <h1>Mouse Move Events</h1> <div id="content"> <div id="box"> Test Box </div> </div> </body>
在move.js脚本文件中注册了所有鼠标移动事件:
ADS.addEvent(window,'load',function(W3CEvent) { // 记录事件类型和对象 function logit(W3CEvent) { switch(this.nodeType) { case ADS.node.DOCUMENT_NODE: ADS.log.write(W3CEvent.type + ' on the document'); break; case ADS.node.ELEMENT_NODE: ADS.log.write(W3CEvent.type + ' on the box'); break; } } ADS.addEvent(document,'mousemove',logit); ADS.addEvent(document,'mouseover',logit); ADS.addEvent(document,'mouseout',logit); var box = document.getElementById('box'); ADS.addEvent(box,'mousemove',logit); ADS.addEvent(box,'mouseover',logit); ADS.addEvent(box,'mouseout',logit); });
鼠标单击事件
□ 当用户在页面上单击鼠标时,在发生鼠标移动事件的同时还会启动另一条事件链:
□ 当在对象上方按下鼠标按键时触发mousedown事件
□ 但释放鼠标按键时触发mouseup事件
□ 只有在鼠标保持不动时才触发click事件
□ 如果快速按两次按键,则会在click事件后发生dblclick事件
需要注意的是,只有当鼠标指针保持不动的情况下,以上的顺序才是正确的。下面的示例和move.js非常类似,只是修改了事件侦听部分的代码。为document和box元素注册的是click、dblclick、mousedown和mouseup。
效果演示
ADS.addEvent(window,'load',function(W3CEvent) { // 记录事件类型和对象 function logit(W3CEvent) { switch(this.nodeType) { case ADS.node.DOCUMENT_NODE: ADS.log.write(W3CEvent.type + ' on the document'); break; case ADS.node.ELEMENT_NODE: ADS.log.write(W3CEvent.type + ' on the box'); break; } } ADS.addEvent(document,'mousedown',logit); ADS.addEvent(document,'mouseup',logit); ADS.addEvent(document,'click',logit); ADS.addEvent(document,'dblclick',logit); var box = document.getElementById('box'); ADS.addEvent(box,'mousedown',logit); ADS.addEvent(box,'mouseup',logit); ADS.addEvent(box,'click',logit); ADS.addEvent(box,'dblclick',logit); });
下图在示例文件的页面上单击并释放鼠标指针不会触发click事件的示意图:
它会在ADS.log对象创建的日志窗口中输出以下两个事件:
(1) document对象上的mousedown事件
(2) document对象上的mouseup事件
在单击和释放鼠标之间,由于拖动了鼠标指针,所以不会发生click事件:
而下图在页面上单击并在box元素上释放鼠标指针
会输出以下事件:
(1) document对象上的mousedown事件
(2) box对象上的mouseup事件
(3) document对象上的mouseup事件
之所以在box上面触发mouseup事件,是因为在box上面释放了鼠标键。虽然mousedown和mouseup是相关的,但它们并不一定成对触发。
键盘事件
当某个键被按下时,浏览器调用事件的顺序与click事件相同,只不过都是按键有关的事件:
(1) keydown:按下某个键时触发
(2) keyup:释放某个键时触发
(3) keypress:在keyup事件之后触发,表示按下了某个键
表单事件
1. submit和reset事件
submit事件:单击提交按钮,或者按下键盘中的某个键将表单提交到服务器时触发
reset事件:重置表单时触发
利用submit和reset事件可以进行客户端表单验证等操作。
效果演示
下面的示例是一个HTML表单:
<form action="" method="post" id="canadianAddress"> <div> <label for="name">Name</label> <input type="text" id="name" name="name"/> </div> <div> <label for="postalCode">Postal Code (required)</label> <input type="text" id="postalCode" name="postalCode" class="required"/> <p>In the format A#A #A#</p> </div> <div> <label for="street">Street</label> <input type="text" id="street" name="street"/> </div> <div> <label for="city">City</label> <input type="text" id="city" name="city"/> </div> <div> <label for="province">Province</label> <input type="text" id="province" name="province"/> </div> <div class="buttons"> <input type="submit" value="submit" /> </div> </form>
为了验证表单邮政编码格式的正确性,本例中包含了一个submit事件侦听器:
function isPostalCode(s) { return s.toUpperCase().match( /[A-Z][0-9][A-Z]\s*[0-9][A-Z][0-9]/i ); } ADS.addEvent(window,'load',function() { ADS.addEvent( document.getElementById('canadianAddress'), 'submit', function(W3CEvent) { var postalCode = document.getElementById('postalCode').value; // 检查格式 if (!isPostalCode(postalCode)) { alert('That\'s not a valid Canadian postal code!'); // 取消提交表单的操作 ADS.preventDefault(W3CEvent); } } ); });
当邮政编码的格式填写不正确时,submit事件会提示错误信息:
2. blur和focus事件
focus事件:用户单击一个表单元素,或者通过tab键切换到一个表单元素时触发
blur事件:单击表单元素之外的区域,或者通过tab键离开该表单元素时触发
下面的示例利用了focus和blur事件来切换样式,从视觉上表示表单元素的填写状态:
ADS.addEvent(window,'load',function() { // 初始化样式 var postalCode = document.getElementById('postalCode'); postalCode.className = 'inputMissing'; // 获得焦点时 ADS.addEvent(postalCode,'focus',function(W3CEvent) { //改变样式 this.className = 'inputEditing'; }); // 失去焦点时 ADS.addEvent(postalCode,'blur',function(W3CEvent) { if(this.value == '') { // 没有填写内容时 this.className = 'inputMissing'; } else if(!isPostalCode(this.value)) { // 内容无效时 this.className = 'inputInvalid'; } else { // 内容填写正确 this.className = 'inputComplete'; } }); });
这些事件侦听器通过修改文本框的className属性,实现了文本框的样式随着获得和失去交点而改变。当编辑邮政编码时,触发focus事件修改相应的样式:
当离开邮政编码框时,浏览器会触发blur事件,同时事件侦听器检测文本框中是否包含有效的信息,并重新应用适当的样式:
3. change事件
change事件:触发focus事件之后,在focus和blur事件之间修改元素的值是触发。
例如,当填写完邮政编码之后,change事件会向服务器端脚本发送一个XMLHttpRequest请求,利用服务器端的服务来验证邮政编码的格式。与此同时,服务器端脚本可以查询街道、城市以及省份的信息,并自动生成表单中其它字段的信息:
ADS.addEvent(window,'load',function() { var postalCode = ADS.$('postalCode'); ADS.addEvent(postalCode,'change',function(W3CEvent) { var newPostalCode = this.value if(!isPostalCode(newPostalCode)) return; var req = new XMLHttpRequest(); req.open('POST', 'server.js?postalCode=' + newPostalCode, true); req.onreadystatechange = function() { if (req.readyState == 4) { eval(req.responseText); if(ADS.$('street').value == '') { ADS.$('street').value = street; } if(ADS.$('city').value == '') { ADS.$('city').value = city; } if(ADS.$('province').value == '') { ADS.$('province').value = province; } } } req.send(); }); });
这里引用的服务器端脚本server.js,也只是一个包含街道、城市以及省份信息的文件:
var street = '123 Somewhere'; var city = 'Ottawa'; var province = 'Ontario';
最终的结果是既验证了邮政编码信息的真实性,同时又获得了街道、城市以及省份信息,如下图所示:
转载请注明:陈童的博客 » ADS4.1 响应用户操作和事件——事件的类型