在jQuery中有多个用于绑定事件处理程序的方法。它们是:
为什么jQuery要提供如此多的事件处理方法呢?这和jQuery的版本发展历史有着密切的关系。我们将在这篇文章中一一介绍。
bind()
bind()
方法为每个匹配元素的特定事件绑定事件处理函数。它的语法格式为:
bind(type,[data],fn)
参数:
type
:含有一个或多个事件类型的字符串,由空格分隔多个事件。比如"click"或"submit",还可以是自定义事件名。data
:作为event.data属性值传递给事件对象的额外数据对象。fn
:绑定到每个匹配元素的事件上面的处理函数。
第三个参数还可以是一个布尔值。将第三个参数设置为false会使默认的动作失效。
bind()
方法的第二个参数可以是一个对象,它用于为事件传递数据。例如下面的代码:
$("#btn").bind("click",{"name":"zs","age":12},function(event){ console.info(event.data.name); //输出zs });
bind()
方法可以同时绑定多个事件类型。例如:
$('#bar').bind('mouseenter mouseleave', function() { $(this).toggleClass('actived'); });
bind()
方法可以同时绑定多个事件类型/处理程序。例如:
$("#btn").bind({ click:function(){$("p").slideToggle();}, mouseover:function(){$("body").css("background-color","red");}, mouseout:function(){$("body").css("background-color","#FFFFFF");} });
使用bind()
方法来绑定事件会有一些问题存在:当新增加元素的时候,没有办法为新元素绑定事件,需要重新使用bind()
来绑定事件。例如有如下的HTML结构:
<div id="container"> <div class="row">div1</div> </div>
我们为div.row
绑定一个鼠标点击事件:
$(function(){ $(".row").bind("click",function(event){ alert($(this).html()+"is clicked!"); }) })
此时,点击div1时会弹出对话框。接下来我们动态的在div#container
中添加一个div元素,它的class同样为.row
。
$(function(){ $(".row").bind("click",function(event){ alert($(this).html()+"is clicked!"); }) // 动态添加一个新的div $("#container").append("<div class="row">div2</div> ") })
这时,虽然新增加的div的class也是.row
,但是并没有绑定click
事件,鼠标点击div2不会有任何动作发生。为解决这些问题,jQuery在后续版本中增加了live()
、die()
、on()
、delegate()
等一系列的绑定事件的方法。
unbind()
unbind()
方法是bind()
的反向操作,从每一个匹配的元素中删除绑定的事件。如果没有参数,则删除所有绑定的事件。你可以将使用bind()
注册的自定义事件取消绑定。如果提供了事件类型作为参数,则只删除该类型的绑定事件。如果把在绑定时传递的处理函数作为第二个参数,则只有这个特定的事件处理函数会被删除。
unbind()
方法的语法格式为:
unbind(type,[data|fn]])
参数:
type
:删除元素的一个或多个事件,由空格分隔多个事件值。data
:作为event.data属性值传递给事件对象的额外数据对象。fn
:要从每个匹配元素的事件中反绑定的事件处理函数。
unbind()
方法的第三个参数还可以是一个布尔值。将第三个参数设置为false会使默认的动作失效。
例如下面的代码取消匹配元素的所有事件绑定。
$("selector").unbind()
下面的代码取消匹配元素的click事件绑定。
$("selector").unbind("click")
one()
one()
方法为每一个匹配元素的特定事件绑定一个一次性的事件处理函数。也就是说,通过one()
执行的事件只会被执行一次。
在每个对象上,这个事件处理函数只会被执行一次。其它规则与bind()
函数相同。这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。
one()
方法的语法为:
one(type,[data],fn)
参数:
type
:添加到元素的一个或多个事件。由空格分隔多个事件。必须是有效的事件。data
:将要传递给事件处理函数的数据映射。fn
:每当事件触发时执行的函数。
例如下面的代码,列表中的列表项只会在第一次被点击时执行相应的代码。
$("li").one("click", function(){ alert( $(this).html() ); });
trigger()
trigger()
方法在每一个匹配的元素上触发某类事件。
这个函数也会导致浏览器同名的默认行为的执行。比如,如果用trigger()
触发一个表单提交'submit',则同样会导致浏览器提交表单。如果要阻止这种默认行为,应返回false。
你也可以触发由bind()
注册的自定义事件而不限于浏览器默认事件。
jQuery也支持 命名空间事件。这允许你触发或者解除绑定一组特定的事件处理函数,而无需一一个指定。你可以在事件类型后面加上感叹号 ! 来只触发那些没有命名空间的事件处理函数。
trigger()
方法的语法格式为:
trigger(type,[data])
参数:
type
:一个事件对象或者要触发的事件类型。data
:传递给事件处理函数的附加参数。
例如使用下面的代码可以提交表单:
$("form:first").trigger("submit")
下面的例子展示了通过trigger()
方法触发另一个元素通过bind()
绑定的事件。
<button id="btn">点击一下</button> <a href="#" id="link">link</a> $(function(){ $("*").bind("click",function(event,a,b){ console.info(event.currentTarget.id+"--"+(a+b)); }); $("a[href='#']").bind("click",function(event){ //使用trigger带来的好处有: //1、可以在其它对象中调用另外一个事件 //2、可以为事件传递参数 //3、使用trigger依然存在事件冒泡 $("#btn").trigger("click",[2,3]); event.preventDefault(); }) });
上面的代码为页面中的所有元素绑定了click事件。然后为超链接绑定一个click鼠标点击事件,在该事件中触发按钮的click事件。
使用trigger()
给我们带来的好处有:
- 可以在其它对象中调用另外一个事件。
- 可以为事件传递参数,就像上面的例子一样。
另外,使用trigger()
依然会产生事件冒泡。
triggerHandler()
triggerHandler()
方法会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作,也不会产生事件冒泡。
triggerHandler()
方法的行为表现与trigger()
类似,但有以下三个主要区别:
- 1、不会触发浏览器默认事件。
- 2、只触发jQuery对象集合中第一个元素的事件处理函数。
- 3、这个方法返回的是事件处理函数的返回值,而不是据有可链性的jQuery对象。此外,如果最开始的jQuery对象集合为空,则这个方法返回 undefined 。
triggerHandler()
方法的语法格式为:
triggerHandler(type, [data])
参数:
type
:要触发的事件类型。data
:传递给事件处理函数的附加参数。
例如:如果你对一个focus事件执行了triggerHandler()
,浏览器默认动作将不会被触发,只会触发你绑定的动作。
<button id="old">.trigger("focus")</button> <button id="new">.triggerHandler("focus")</button><br/><br/> <input type="text" value="To Be Focused"/>
$("#old").click(function(){ $("input").trigger("focus"); }); $("#new").click(function(){ $("input").triggerHandler("focus"); }); $("input").focus(function(){ $("<span>Focused!</span>").appendTo("body").fadeOut(1000); });
live()
由于bind()
方法在新添加元素时无法为新元素绑定事件,所以jQuery提供了live()
方法来绑定事件。
live()
方法的语法格式为:
live(type, [data], fn)
同样使用上面bind()
方法中的例子,只要将bind()
修改为live()
,就可以解决新元素的事件绑定问题。
<div id="container"> <div class="row">div1</div> </div>
$(function(){ $(".row").live("click",function(event){ alert($(this).html()+"is clicked!"); }) // 动态添加一个新的div $("#container").append("<div class="row">div2</div> ") })
使用上面的代码,新添加的div2元素也会绑定click事件。
live()
方法的原理是事件委托。而事件委托是通过冒泡机制来实现的。下面我们来分析一下它的实现原理。
在jQuery的文档筛选中有一个重要的方法:closest()
。这是在jQuery1.3中新增的方法,它用于从元素本身开始,逐级向上级元素匹配,并返回最先匹配的元素。
closest会首先检查当前元素是否匹配,如果匹配则直接返回元素本身。如果不匹配则向上查找父元素,一层一层往上,直到找到匹配选择器的元素。如果什么都没找到则返回一个空的jQuery对象。
例如考虑下面的HTML代码:
<ul> <li>item1</li> <li> <ul> <li>item4</li> <li id="item">item2</li> </ul> </li> <li>item3</li> </ul>
执行下面的jQuery代码:
$("#item").closest("ul").css("color","#ffaaaa");
上面的代码返回#item
列表项最接近的ul
元素,得到的结果如下图所示:
如果将代码改为:
$("#item").closest("li").css("color","#ffaaaa");
得到的结果就是#item
这个列表项本身。
由于closest可以从元素自己本身开始查找,所以closest非常适合用于做事件委派。
那么如何做到事件委派呢?事件委派是指绑定在祖先元素上的事件处理函数可以对在后代上触发的事件作出回应。因为所有的元素事件都会通过冒泡到根元素中,所以我们只需要在文档根元素上绑定事件即可,然后在处理时,判断一下该事件是否是我们需要处理的对象就可以了。
<div id="container"> <div class="row">div1</div> <ul> <li>item1</li> <li> <ul> <li>item4</li> <li id="item">item2</li> </ul> </li> <li>item3</li> </ul> </div>
/* 模拟事件委派 */ $(function(){ $(document).bind("click",function(event){ var obj = $(event.target).closest(".row"); if((obj[0]) == event.target) alert("find!"); }) $("#container").append("<div class='row'>div2</div>"); });
执行上面的代码后,原来的div1和新插入的div2在鼠标点击时都会弹出对话框,而列表项元素被点击时不会有任何的动作发生。这就是事件委派机制。
对于live()
方法而言就是使用事件委派的机制,但是使用这个方式会带来如下问题:
- 1、每一个事件都会冒泡到document上面去,影响性能。
- 2、使用live不支持一些特殊的事件。
为了提高性能,live()
方法提供了第二个参数来指定绑定的上下文,说明事件委派的根对象是什么。例如:
<div id="container"> <div class="row">div1</div> </div>
$(".row","#container").live("click",function(event){ alert($(this).html()) })
此时,live()
绑定的上下文是#container
容器,也就是说事件只会冒泡到这个容器上,不会再冒泡到文档的根元素。
die()
die()
方法是从元素中删除先前用live()
方法绑定的所有事件。
如果die()
方法不带参数,则所有绑定的live事件都会被移除。如果提供了type参数,那么会移除对应的live事件。如果也指定了第二个参数function,则只移出指定的事件处理函数。
die()
方法的语法格式为:
die(type, [fn])
参数:
type
:要移除的一个或多个事件处理程序。由空格分隔多个事件值。必须是有效的事件。fn
:要移除的函数。
例如下面的代码给按钮解除click事件。
function aClick() { $("div").show().fadeOut("slow"); } $("#unbind").click(function () { $("#theone").die("click", aClick) });
delegate()
由于live()
方法的写法比较怪异,jquery在1.4之后提供了另一个事件委派的方法:delegate()
。
delegate()
方法的语法格式为:
delegate(selector,[type],[data],fn)
参数:
selector
:选择器字符串,用于过滤器触发事件的元素。type
:附加到元素的一个或多个事件。由空格分隔多个事件值。必须是有效的事件。data
:传递到函数的额外数据。fn
:当事件发生时运行的函数。
例如还是使用前面的例子:
<div id="container"> <div class="row">div1</div> </div>
/* 使用delegate来完成事件委派 */ $("#container").delegate(".row","click",function(event){ alert($(this).html()); }) $("#container").append("<div class='row'>div2</div>");
$("#container")
表示的是绑定的上下文,它指明事件委派的根对象。
delegate()
方法的第一个参数表示绑定事件的对象。第二个参数是绑定的事件。
在jquery1.4之后,live()
和die()
方法已不建议使用,未来的jquery版本中有可能会删除这两个方法。
undelegate()
undelegate()
方法删除由delegate()
方法添加的一个或多个事件处理程序。
undelegate()
方法的语法格式为:
undelegate([selector,[type],fn])
参数:
selector
:需要删除事件处理程序的选择器。type
:需要删除处理函数的一个或多个事件类型。 由空格分隔多个事件值。必须是有效的事件。fn
:要删除的具体事件处理函数。
例如下面的代码从列表元素中删除由delegate()
方法添加的所有事件处理器:
$("li").undelegate();
on()
在jquery1.7之前,用户可以有多种方法来完成事件的委派。在jquery1.7之后,jquery使用on()
方法来统一代替bind()
,live()
和delegate()
。
on()
方法的语法格式为:
on(events,[selector],[data],fn)
参数:
events
:一个或多个用空格分隔的事件类型和可选的命名空间,如"click"或"keydown.myPlugin"。selector
:一个选择器字符串用于过滤器的触发事件的选择器元素的后代。如果选择的< null或省略,当它到达选定的元素,事件总是触发。data
:当一个事件被触发时要传递event.data给事件处理函数。fn
:该事件被触发时执行的函数。 false 值也可以做一个函数的简写,返回false。
例如下面的代码使用on()
来模拟bind()
方法。
$(".row").on("click",function(event){ alert($(this).html()); })
当on()
方法的第二个参数没有设定时,jquery就认为是对.row
元素绑定事件,这实际是在模拟bind()
方法。
而当第二个参数有值的时候,调用的对象就作为委派的根对象。例如下面的代码:
$("#container").on("click",".row",function(event){ alert($(this).html()); })
提示:在我们使用jquery进行事件处理的时候,应该使用的是on()
方法,而不再使用live()
和delegate()
方法。
off()
off()
方法移除用on()
绑定的事件处理程序
off()
方法的语法格式为:
off(events,[selector],[fn])
参数:
events
:一个或多个空格分隔的事件类型和可选的命名空间,或仅仅是命名空间。selector
:一个最初传递到.on()事件处理程序附加的选择器。fn
:事件处理程序函数以前附加事件上,或特殊值false。
例如下面的代码从列表元素中删除由on()
方法添加的所有事件处理器:
$("li").off();