1.基本用法:
javascript的事件模型,采用”冒泡”模式,也就是说,子元素的事件会逐级向上”冒泡”,成为父元素的事件。
利用这一点,可以大大简化事件的绑定。比如,有一个表格(table元素),里面有100个格子(td元素),现在要求在每个格子上面绑定一个点击事件(click),请问是否需要将下面的命令执行100次?
$("td").on("click", function(){ $(this).toggleClass("click"); });
回答是不需要,我们只要把这个事件绑定在table元素上面就可以了,因为td元素发生点击事件之后,这个事件会”冒泡”到父元素table上面,从而被监听到。
因此,这个事件只需要在父元素绑定1次即可,而不需要在子元素上绑定100次,从而大大提高性能。这就叫事件的”委托处理”,也就是子元素”委托”父元素处理这个事件。
$("table").on("click", "td", function(){ $(this).toggleClass("click"); });
更好的写法,则是将事件绑定在document对象上面。
$(document).on("click", "td", function(){ $(this).toggleClass("click"); });
如果要取消事件的绑定,就使用off()方法。
$(document).off("click", "td");
用jquery来实现的时候,方法有两种。
第一种是采用.delegate()方法:http://www.css88.com/jqapi-1.9/delegate/
$(“table”).delegate(“td”, ”click”, function(){$(this).toggleClass(“click”); });
第二种是采用.live()方法:http://www.css88.com/jqapi-1.9/live/
$(“table”).each(function(){$(“td”, this).live(“click”, function(){ $(this).toggleClass(“click”); }); });
这 两种写法基本等价。唯一的区别在于,.delegate()是当事件冒泡到指定的父元素时触发,.live()则是当事件冒泡到文档的根元素后触发,因 此.delegate()比.live()稍快一点。此外,这两种方法相比传统的.bind()方法还有一个好处,那就是对动态插入的元素也有 效,.bind()只对已经存在的DOM元素有效,对动态插入的元素无效。
根据测试,委托处理比不委托处理,快了几十倍。在委托处理的情况下,.delegate()又比.live()大约快26%。
文档中说:从jQuery1.7开始, .delegate()方法和.live()
方法已经过时了。使用.on()
附加事件处理程序。 旧版本的jQuery中用户,应优先使用.delegate()
来取代.live();
这个方法提供了一种手段,将委托的事件处理程序附加到一个页面的document
元素,从而简化了在页面上动态添加的内容上事件处理的使用。直接与委派事件的讨论,请查看.on()
方法的更多信息。
在其继承者重写.live()
方法是简单的;以下是三种事件添加方法的模板,它们是等价的:
1 $(selector).live(events, data, handler); // jQuery 1.3+ 2 $(document).delegate(selector, events, data, handler); // jQuery 1.4.3+ 3 $(document).on(events, selector, data, handler); // jQuery 1.7+
2.原理部分
.on( events [, selector ] [, data ], handler(eventObject) )
描述: 在选定的元素上绑定一个或多个事件处理函数。
用法1:.on(events [,selector][,data],handler(eventObject) )
-
events类型: String一个或多个空格分隔的事件类型和可选的命名空间,或仅仅是命名空间,比如"click", "keydown.myPlugin", 或者 ".myPlugin"。
-
selector类型: String一个选择器字符串,用于过滤出被选中的元素中能触发事件的后代元素。如果选择器是
null
或者忽略了该选择器,那么被选中的元素总是能触发事件。 -
data类型: Anything当一个事件被触发时,要传递给事件处理函数的
event.data
。 -
handler(eventObject)类型: Function()事件被触发时,执行的函数。若该函数只是要执行
return false
的话,那么该参数位置可以直接简写成false
。
用法2:.on(events [,selector][,data])
-
events类型: PlainObject一个对象,键是由一个或多个由空格分隔的事件类型及可选的名字空间,值是这些事件类型所对应的事件处理函数。
-
selector类型: String一个选择器字符串,用于过滤出被选中的元素中能触发事件的后代元素。如果选择器是
null
或者忽略了该选择器,那么被选中的元素总是能触发事件。 -
data类型: Anything当一个事件被触发时,要传递给事件处理函数的
event.data
。
2.1 Event names and namespaces(事件名称和命名空间)
任何事件的名称,可以作为events
参数。jQuery将通过所有浏览器的标准JavaScript事件类型,当用户操作事件,如click
,浏览器会调用handler
参数的函数。此外,.trigger()
方法可以触发标准的浏览器事件 和 自定义事件名绑定的处理程序。
事件名称可以添加指定的event namespaces(命名空间) 来简化删除或触发事件。例如,"click.myPlugin.simple"
为 click 事件同时定义了两个命名空间 myPlugin 和 simple。通过上述方法绑定的 click 事件处理,可以用.off("click.myPlugin")
或 .off("click.simple")
删除绑定到相应元素的Click事件处理程序,而不会干扰其他绑定在该元素上的“click(点击)” 事件。命名空间类似CSS类,因为它们是不分层次的;只需要有一个名字相匹配即可。以下划线开头的名字空间是供 jQuery 使用的。
在.on()
方法的第二种用法中,events
参数是一个JavaScript对象或者键值对。键等同于events
参数,用空格分隔的事件名称字符串和可选命名空间。每个键的值是一个函数(或false
的值),相当于 handler
参数,但是该值并不是方法中的最后一个参数。在其它方面,这两种形式在下面描述的内容中其行为都是相同的。
2.2 Deriect and delegated events(直接和委托的事件)
大多数浏览器事件冒泡, 或者 传播,都是由内到外的,从在文档最深处的元素( 事件目标 event target)开始, 一路传递到body和document
元素。(愚人码头注:事件冒泡简单的说就是,在冒泡路径上所有绑定了相同事件类型的元素上都会触发这些类型的事件。)在Internet Explorer 8和更低,一些事件,如change
和 submit
本身不泡沫,但 jQuery 为了跨浏览器一致性, jQuery 在这些事件上模拟了冒泡行为。
如果省略selector
或者是null,那么事件处理程序被称为直接事件 或者 直接绑定事件 。每次选中的元素触发事件时,就会执行处理程序,不管它直接绑定在元素上,还是从后代(内部)元素冒泡到该元素的
当提供selector
参数时,事件处理程序是指为委派 事件(愚人码头注:通常也有很多人叫它代理事件)。事件不会在直接绑定的元素上触发,但当selector
参数选择器匹配到后代(内部元素)的时候,事件处理函数才会被触发。jQuery 会从 event target 开始向上层元素(例如,由最内层元素到最外层元素)开始冒泡,并且在传播路径上所有绑定了相同事件的元素若满足匹配的选择器,那么这些元素上的事件也会被触发。
事件处理只能绑定在当前被选中的元素上;而且,在您的代码调用.on()
的时候,他们必须在页面文档中已经存在。为了确保目前的元素可以被选择的(愚人码头注:即,存在),最好是在 document 的 ready 事件中进行事件绑定。如果新的HTML被注入页面时,新的HTML放置到页面后,事件会绑定到匹配选择器(selector
参数)的元素。或者,使用委派事件绑定事件处理程序,如下所述。
委托事件有一个优势,他们能在后代元素添加到文档后,可以处理这些事件。 在确保所选择的元素已经存在的情况下,进行事件绑定时,您可以使用委派的事件,以避免频繁的绑定事件及解除绑定事件。 例如,这个已经存在的元素可以是 Model-View-Controller(模型 - 视图 - 控制器)模式中 View(视图) 的一个容器元素,或document
。如果想监视所有文档中的冒泡事件的话。在加载任何其它 HTML 之前,document
元素在 head
中就是有效的,所以您可以安全的在head
中进行事件绑定,而不需要等待文档加载完。
除了可以给未创建的后代元素绑定事件外(即上面提到的优势),代理事件的另一个好处就是,当需要监视很多元素的时候,代理事件的开销更小。例如,在一个表格的 tbody
中含有 1,000 行,下面这个例子会为这 1,000 元素绑定事件:
$("#dataTable tbody tr").on("click", function(event){ alert($(this).text()); });
委派事件的方法只有一个元素的事件处理程序,tbody,并且事件只会向上冒泡一层(从被点击的tr
到 tbody
):
$("#dataTable tbody").on("click", "tr", function(event){ alert($(this).text()); });
注意: 委托事件不能用于SVG.
2.3 The event handler and its environment(事件)
handler
参数必须是一个函数(或false
值,见下文), 除非你传递一个对象给events
参数。 您可以提供一个匿名处理函数给.on()
调用,就像上面例子中的用法,或者可以声明一个函数,然后再将该函数名作为参数:
function notify() { alert("clicked"); } $("button").on("click", notify);
当浏览器触发一个事件或其他JavaScript调用的jQuery的.trigger()
方法,jQuery传递一个event object
给这个处理程序,它可以用来分析和改变事件的状态。这个对象是由浏览器提供一个数据的标注化子集;您需要浏览器自己的未经修改的原始 event 对象,您可以使用event.originalEvent
得到。例如, event.type
包含事件的名称(例如, "resize" )和event.target
表示事件除非的最深元素(最内层)。
默认情况下,大多数事件的冒泡从最初的 event target(目标元素) 开始的,直到document
元素。每个元素都沿着DOM层级这条路,jQuery会调用任何匹配的已被绑定的事件处理程序。一个处理程序可以调用的event.stopPropagation()
防止事件向上冒泡文档树( 从而防止这些元素的处理程序运行)。任何绑定到当前元素上的其他处理程序都将运行,为了防止这种情况,可以调用event.stopImmediatePropagation()
。(绑定在元素上的事件被调用的顺序和它们被绑定的顺序时一样的。 )
类似地,一个处理程序可以调用的event.preventDefault()
取消浏览器默认操作行为;例如,一个链接上有一个 默认的click
事件。并非所有的浏览器事件的默认操作,并非所有的默认操作可以被取消。有关详细信息,请参阅W3C Events Specification
调用event.stopPropagation()
和 event.preventDefault()
会从一个事件处理程序会自动返回false
。也可以直接将 false
当作 handler
的参数,作为 function(){ return false; }
的简写形式。因此,下面的写法$("a.disabled").on("click", false);
将会阻止所有含有 "disabled" 样式的链接的默认行为,并阻止该事件上的冒泡行为。
当jQuery的调用处理程序时,this
关键字指向的是当前正在执行事件的元素。对于直接事件而言,this
代表绑定事件的元素。对于代理事件而言,this
则代表了与 selector
相匹配的元素。(注意,如果事件是从后代元素冒泡上来的话,那么 this
就有可能不等于 event.target
。)若要使用 jQuery 的相关方法,可以根据当前元素创建一个 jQuery 对象,即使用 $(this)
。
2.4 Passing data to the handler(将数据传递给处理程序)
如果data
参数给.on()
并且不是null
或者 undefined
,那么每次触发事件时,event.data
都传递给处理程序。data
参数可以是任何类型,但如果是字符串类型时,那么selector
参数必须提供,或明确地传递null
,这样的 data 参数不会误认为是选择器。最好是使用一个对象(键值对) ,所以可以作为属性传递多个值。
jQuery的1.4 ,相同的事件处理程序可以多次绑定到一个元素。这对于使用 event.data
功能,或者在闭包中使用唯一的数据时是特别有用的。例如:
function greet(event) { alert("Hello "+event.data.name); } $("button").on("click", { name: "Karl" }, greet); $("button").on("click", { name: "Addy" }, greet);
按一下按钮时,上面的代码会产生两个不同的警报。
除了可以向 .on()
方法传入 data
参数外,还可以向 .trigger() 或 .triggerHandler() 中传入该参数。
2.5 Event performance(事件性能)
在大多数情况下,一个事件如click
很少发生,性能表现并不显注。但是,高频率事件比如mousemove
或者 scroll
可以每秒触发几十个次,在这种情况下明智地使用事件变得更加重要。可以按如下的办法提高事件的性能:减少事件处理函数中的工作量;对于在事件处理函数中要用到的信息做好缓存而不是再重新计算一次;或使用setTimeout
限制的页面更新的实际次数。
许多委派的事件处理程序绑定到 document 树的顶层附近,可以降低性能。每次发生事件时,jQuery 需要比较从 event target(目标元素) 开始到文档顶部的路径中每一个元素上所有该类型的事件。为了获得更好的性能,在绑定代理事件时,绑定的元素最好尽可能的靠近目标元素。避免在大型文档中,过多的在 document
或 document.body
上添加代理事件。
jQuery可以非常迅速处理tag#id.class
形式的简单选择器,当它们是用来过滤委派事件。所以"#myForm"
,"a.external"
, 和 "button"
都是快速选择器。若代理事件的选择器使用了过于复杂的形式,特别是使用了分层选择器的情况,虽然说这样做会大大的降低性能,但是对于大多数应用而言,它的速度依然是足够快的。通过为寻找更合适的元素绑定事件的方法,就可以很简单的避免使用分层选择器的情况。例如,使用$("#commentForm").on("click", ".addNew", addComment)
而不是$("body").on("click", "#commentForm .addNew", addComment)
。
3. Additional notes(其他注意事项)
有一些事件的速记方法比如.click()
可用于附加或触发事件处理程序。对于速记方法的完整列表, 参见events category
虽然不建议,伪类事件名称"hover"
可以作为"mouseenter mouseleave"
的缩写使用。不要与 接受两个函数的.hover()
方法混淆,这里只用一个处理函数绑定到伪类事件名称"hover"
;处理程序应该检查的event.type
以确定是否是mouseenter
或 mouseleave
事件。
jQuery的事件系统需要一个DOM元素可以通过元素的属性附加数据,使事件就可以被跟踪和传递。object
, embed
, 和applet
元素不能绑定数据,因此不能有jQuery的事件绑定。
W3C指定明确指定focus
和 blur
事件没有冒泡,但是jQuery定义的跨浏览器的focusin
和 focusout
事件,并且可以冒泡。当focus
和 blur
绑定委派的事件处理程序时,jQuery分析名称,并提供将他们分别交付给focusin
和focusout
。为了保持一致性和清晰度,使用冒泡事件类型的名称。
在所有的浏览器,load
,scroll
, 和 error
事件(例如, 在一个 <img>
元素上)不会冒泡。在Internet Explorer 8和更低,paste
和 reset
事件不会冒泡,这样的事件是不支持委派使用,但若事件处理函数是直接绑定在产生事件的元素上的话,是可以使用这些事件的。
window
对象上的error
事件使用非标准的参数和返回值约定,所以jQuery 不支持该事件。作为替代,直接用window.onerror
属性分配一个处理函数。
例子:
Example: 当点击段落时,显示该段落中的文本:
1
2
3
|
$("p").on("click", function(){ alert( $(this).text() ); }); |
Example: 向事件处理函数中传入数据,并且在事件处理函数中通过名字来获取传入的数据:
1
2
3
4
|
function myHandler(event) { alert(event.data.foo); } $("p").on("click", {foo: "bar"}, myHandler) |
Example: 取消表单的提交动作,并且通过返回 false 的方法来防止事件冒泡:
1
|
$("form").on("submit", false) |
Example: 通过使用 .preventDefault(),仅取消默认的动作。
1
2
3
|
$("form").on("submit", function(event) { event.preventDefault(); }); |
Example: 通过使用 .stopPropagation(),防止提交事件的冒泡行为,但是并不禁止提交行为。
1
2
3
|
$("form").on("submit", function(event) { event.stopPropagation(); }); |
examples: