ADS4.1 响应用户操作和事件——事件的类型

前端技术 everyinch 21302℃ 0评论

事件在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);
	
});

下图展示了鼠标指针从左边移动到右边的事件:
blog_mousemove

鼠标单击事件

□ 当用户在页面上单击鼠标时,在发生鼠标移动事件的同时还会启动另一条事件链:
□ 当在对象上方按下鼠标按键时触发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事件的示意图:
blog_mouseclick1
它会在ADS.log对象创建的日志窗口中输出以下两个事件:
(1) document对象上的mousedown事件
(2) document对象上的mouseup事件
在单击和释放鼠标之间,由于拖动了鼠标指针,所以不会发生click事件:

而下图在页面上单击并在box元素上释放鼠标指针
blog_mouseclick2
会输出以下事件:
(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事件会提示错误信息:
blog_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事件修改相应的样式:
ads4_focus
当离开邮政编码框时,浏览器会触发blur事件,同时事件侦听器检测文本框中是否包含有效的信息,并重新应用适当的样式:
blog_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';

最终的结果是既验证了邮政编码信息的真实性,同时又获得了街道、城市以及省份信息,如下图所示:
blog_change



转载请注明:陈童的博客 » ADS4.1 响应用户操作和事件——事件的类型

喜欢 (0)
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址

无觅相关文章插件,快速提升流量