事件是脚本编程的灵魂. 所以本章内容也是jQuery学习的重点. 本文将对jQuery中的事件处理以及事件对象进行详细的讲解.
本篇文章是至今为止本系列内容最多的一篇, 足以可见其重要性. 大家反映要多列举示例. 我会在时间允许的情况下尽量多列举示例. 真正的投入生产使用的实例暂时还无法加入到文章中, 但是可能最后我会列举一些作品供大家借鉴. 另外本人水平有限, 因为我不是UI设计师. 文章可能有错误的地方, 希望大家帮忙指出, 一起学习一起进步. 在技术的世界里我们是没有任何利益瓜葛. 希望大家都抱着彼此鼓励的心态, 对于回复中的激进评论我也都会考虑, 但是希望能够彼此尊重, 保护博客园这片程序员的净土!
曾经在我的 "Javascript公共脚本库系列(二): 添加事件多播委托的方法" 和 "Javascript公共脚本库系列(三): 格式化事件对象/事件对象详解" 两篇文章中, 曾讲解过javascript中的事件和事件对象.
首先看一下我们经常使用的添加事件的方式:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>javascript中的事件</title> <script type="text/javascript" src="scripts/jquery-1.3.2-vsdoc2.js"></script> <script type="text/javascript"> $(function() { document.getElementById("testDiv2").onclick = showMsg; }) function showMsg(event) { alert("!!!"); } </script> </head> <body> <div id="testDiv1" onclick="showMsg();">单击事件 1</div> <div id="testDiv2">单击事件 2</div> </body> </html>
我们最常使用为元素添加onclick元素属性的方式添加事件.
为testDiv2的添加onclick事件的方式是修改Dom属性.
在上一章中已经说明了什么是元素属性, 什么是Dom属性.这两种方式的效果相同. 当单击div时会显示提示框.
请注意, 虽然效果相同, 但是并不等效.
document.getElementById("testDiv2").onclick = showMsg;
等效于:
<div id="testDiv1" onclick="alert("!!!");">单击事件 1</div>
注意两者的区别了吗? 我们常用的修改元素属性添加事件的方式, 实际上是建立了一个匿名函数:
document.getElementById("testDiv1").onclick = function(event) { alert("!!!"); };
这个匿名函数的签名和我们手写的showMsg签名相同, 所以可以把showMsg直接赋值给onclick.
这种方式的弊端是:
1. 只能为一个事件绑定一个事件处理函数. 使用"="赋值会把前面为此时间绑定的所有事件处理函数冲掉.
2. 在事件函数(无论是匿名函数还是绑定的函数)中获取事件对象的方式在不同浏览器中要特殊处理:
IE中,事件对象是window对象的一个属性.事件处理函数必须这样访问事件对象:
obj.onclick=function() { var oEvent = window.event; }
在DOM标准中,事件对象必须作为唯一参数传给事件处理函数:
obj.onclick=function() { var oEvent = arguments[0]; }
除了使用argument[0]访问此参数, 我们也可以指定参数名称,上面的代码等同于:
obj.onclick=function(oEvent)
{
}
目前兼容DOM的浏览器有Firefox,Safari,Opera,IE7等.
3. 添加多播委托的函数在不同浏览器中是不一样的.
下面是在"Javascript公共脚本库系列(二): 添加事件多播委托的方法"文章中, 提供的兼容多浏览器添加多播委托的方法:
//统一的为对象添加多播事件委托的方法 /* 参数说明: oTarget : 要添加事件的对象.比如"document". sEventType : 事件类型.比如单击事件"click". fnHandler : 发生事件时调用的方法. 比如一个静态函数"hideCalendar" 使用举例: //单击页面的任何元素,只要没有取消冒泡,都可以关闭日历控件 var cf = document.getElementById("CalFrame"); if( cf != null && hideCalendar != null ) { ScriptHelper.addEventListener( document, "click", hideCalendar ); } */ scriptHelper.prototype.addEventListener = function(oTarget, sEventType, fnHandler) { if( oTarget.addEventListener )//for dom { oTarget.addEventListener( sEventType, fnHandler, false ) } else if( oTarget.attachEvent )//for ie { oTarget.attachEvent( "on" + sEventType, fnHandler); } }
所以我们首先应该摒弃<div onclick="..."></div>这种通过修改元素属性添加事件的方式. 尽量使用添加多播事件委托的方式为一个事件绑定多个事件处理函数, 比如为document对象的单击事件添加一个关闭弹出层的方法, 使用多播就不会影响document对象原有的事件处理函数.
有了jQuery, 我们有了处理对象事件的一系列函数. 上面基础知识还是要懂, 但是再也不用自己去实现处理多播事件委托的函数了. 正所谓有了jQuery, 天天喝茶水. 下面是在jQuery中最常使用的bind()方法举例:
$("#testDiv4").bind("click", showMsg);
我们为id是testDiv4的元素, 添加列click事件的事件处理函数showMsg.
使用jQuery事件处理函数的好处:
1. 添加的是多播事件委托. 也就是为click事件又添加了一个方法, 不会覆盖对象的click事件原有的事件处理函数.
$("#testDiv4").bind("click", function(event) { alert("one"); }); $("#testDiv4").bind("click", function(event) { alert("two"); });
单击testDiv4对象时, 依次提示"one"和"two".
2. 统一了事件名称.
添加多播事件委托时, ie中是事件名称前面有"on". 但是使用bind()函数我们不用区分ie和dom , 因为内部jQuery已经帮我们统一了事件的名称.
3. 可以将对象行为全部用脚本控制.
让HTML代码部分只注意"显示"逻辑. 现在的趋势是将HTML的行为, 内容与样式切分干净. 其中用脚本控制元素行为, 用HTML标签控制元素内容, 用CSS控制元素样式. 使用jQuery事件处理函数可以避免在HTML标签上直接添加事件.
下面是基础的jQuery事件处理函数:
事件处理 Event Handling:
名称 | 说明 | 举例 | 为每一个匹配元素的特定事件(像click)绑定一个事件处理器函数。 | 当每个段落被点击的时候,弹出其文本: $("p").bind("click", function(){ | one( type, [data], fn ) | 为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。 | 当所有段落被第一次点击的时候,显示所有其文本: $("p").one("click", function(){ | trigger( event, [data] ) | 在每一个匹配的元素上触发某类事件。 这个函数也会导致浏览器同名的默认行为的执行。比如,如果用trigger()触发一个'submit',则同样会导致浏览器提交表单。如果要阻止这种默认行为,应返回false。 你也可以触发由bind()注册的自定义事件 | 给一个事件传递参数: $("p").click( function (event, a, b) { | triggerHandler( event, [data] ) | 这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作. | 如果你对一个focus事件执行了 .triggerHandler() ,浏览器默认动作将不会被触发,只会触发你绑定的动作: $("#old").click(function(){ | unbind( type, fn ) | bind()的反向操作,从每一个匹配的元素中删除绑定的事件。 如果没有参数,则删除所有绑定的事件。 你可以将你用bind()注册的自定义事件取消绑定。 如果提供了事件类型作为参数,则只删除该类型的绑定事件。 如果把在绑定时传递的处理函数作为第二个参数,则只有这个特定的事件处理函数会被删除。 | 把所有段落的所有事件取消绑定: $("p").unbind() 将段落的click事件取消绑定: $("p").unbind( "click" ) 删除特定函数的绑定,将函数作为第二个参数传入: var foo = function () { |
名称 | 说明 | 举例 | blur( ) | blur( fn ) | change( ) | change( fn ) | click( ) | click( fn ) | dblclick( ) | dblclick( fn ) | error( ) | error( fn ) | focus( ) | focus( fn ) | keydown( ) | keydown( fn ) | keypress( ) | keypress( fn ) | keyup( ) | keyup( fn ) | load( fn ) | mousedown( fn ) | mouseenter( fn ) | mouseleave( fn ) | mousemove( fn ) | mouseout( fn ) | mouseover( fn ) | mouseup( fn ) | resize( fn ) | scroll( fn ) | Select( ) | Select( fn ) | submit( ) | submit( fn ) | unload( fn ) |
属性名称 | 描述 | 举例 |
type | 事件类型.如果使用一个事件处理函数来处理多个事件, 可以使用此属性获得事件类型,比如click. |
$("a").click(function(event) { alert(event.type); }); |
target | 获取事件触发者DOM对象 |
$("a[href=http://google.com]").click(function(event) { alert(event.target.href); }); |
data | 事件调用时传入额外参数. |
$("a").each(function(i) { $(this).bind('click', {index:i}, function(e){ alert('my index is ' + e.data.index); }); }); |
relatedTarget | 对于鼠标事件, 标示触发事件时离开或者进入的DOM元素 |
$("a").mouseout(function(event) { alert(event.relatedTarget); }); |
currentTarget | 冒泡前的当前触发事件的DOM对象, 等同于this. |
$("p").click(function(event) { alert( event.currentTarget.nodeName ); }); 结果:P |
pageX/Y | 鼠标事件中, 事件相对于页面原点的水平/垂直坐标. |
$("a").click(function(event) { alert("Current mouse position: " + event.pageX + ", " + event.pageY ); }); |
result | 上一个事件处理函数返回的值 |
$("p").click(function(event) { return "hey" }); $("p").click(function(event) { alert( event.result ); }); 结果:"hey" |
timeStamp | 事件发生时的时间戳. |
var last; $("p").click(function(event) { if( last ) alert( "time since last event " + event.timeStamp - last ); last = event.timeStamp; }); |
属性名称 | 描述 | 举例 | altKey | Alt键是否被按下. 按下返回true | ctrlKey | ctrl键是否被按下, 按下返回true | metaKey | Meta键是否被按下, 按下返回true. meta键就是PC机器的Ctrl键,或者Mac机器上面的Command键 | shiftKey | Shift键是否被按下, 按下返回true | keyCode | 对于keyup和keydown事件返回被按下的键. 不区分大小写, a和A都返回65. 对于keypress事件请使用which属性, 因为which属性跨浏览时依然可靠. | which | 对于键盘事件, 返回触发事件的键的数字编码. 对于鼠标事件, 返回鼠标按键号(1左,2中,3右). | screenX/Y | 对于鼠标事件, 获取事件相对于屏幕原点的水平/垂直坐标 |
名称 | 说明 | 举例 |
preventDefault() | 取消可能引起任何语意操作的事件. 比如<a>元素的href链接加载, 表单提交以及click引起复选框的状态切换. |
$("a").click(function(event){ event.preventDefault(); // do something }); |
isDefaultPrevented() | 是否调用过
preventDefault()方法 |
$("a").click(function(event){ alert( event.isDefaultPrevented() ); event.preventDefault(); alert( event.isDefaultPrevented() ); }); |
stopPropagation() | 取消事件冒泡 |
$("p").click(function(event){ event.stopPropagation(); // do something }); |
isPropagationStopped() | 是否调用过
stopPropagation()方法 |
$("p").click(function(event){ alert( event.isPropagationStopped() ); event.stopPropagation(); alert( event.isPropagationStopped() ); }); |
stopImmediatePropagation() | 取消执行其他的事件处理函数并取消事件冒泡. 如果同一个事件绑定了多个事件处理函数, 在其中一个事件处理函数中调用此方法后将不会继续调用其他的事件处理函数. |
$("p").click(function(event){ event.stopImmediatePropagation(); }); $("p").click(function(event){ // This function won't be executed }); |
isImmediatePropagationStopped() | 是否调用过
stopImmediatePropagation()方法 |
$("p").click(function(event){ alert( event.isImmediatePropagationStopped() ); event.stopImmediatePropagation(); alert( event.isImmediatePropagationStopped() ); }); |