.on()

.on( events [, selector ] [, data ], handler )返回类型:jQuery

描述:对选中的元素,针对一个或多个事件,附加一个事件处理函数。

  • 增补版本:1.7.on( events [, selector ] [, data ], handler )

    • events
      类型:String
      一个或多个空格分隔的事件类型,视情况可加命名空间,譬如“click”或“keydown.myPlugin”。
    • selector
      类型:String
      一个选择器字符串,用来筛选选中的元素触发事件后代。如果选择器是null或省略了它,此事件始终在它到达选中的元素时被触发。
    • data
      类型:Anything
      在触发事件时,在event.data中传递到处理函数的数据。
    • handler
      类型:Function( Event eventObject [, Anything extraParameter ] [, ... ] )
      当事件被触发时,要执行的函数。允许值false,作为简单return false的函数的简写。
  • 增补版本:1.7.on( events [, selector ] [, data ] )

    • events
      类型:PlainObject
      一个对象,字符串关键字代表一个或多个空格隔开的事件类型,以及可选的命名空间,此值代表针对该事件被调用的一个处理函数。
    • selector
      类型:String
      一个选择器字符串,筛选被选中的将调用处理函数的元素的后代。如果选择器是null或省略了它,此事件始终在它到达选中的元素时被触发。
    • data
      类型:Anything
      当事件发生时,在event.data中传递给处理函数的数据。

.on()方法把事件处理函数附加到jQuery中当前选中元素的集合。自从jQuery 1.7,.on()方法提供了对附加事件处理函数必要的所有的功能。为了帮助从早的jQuery事件方法转换过来,请参阅.bind().delegate().live()。若要删除用.on()绑定的事件,请参阅.off()。若要附加只运行一次然后自动删除的事件,请参阅.one()

事件名称和命名空间

任何事件名都可以用作events参数。当浏览器由于用户操作,譬如click而生成事件时,jQuery将传递浏览器的标准JavaScript事件类型,调用handler函数。此外,.trigger()方法可以触发标准浏览器事件名称以及自定义事件名称,以调用附加的处理函数。事件名称必须只包含字符数字下划线和冒号字符。

可以用事件命名空间来限定事件名称,它简化了删除事件或触发事件。例如,"click.myPlugin.simple"为特定的点击事件定义了myPlugin和simple命名空间。通过此字符串附加的事件处理函数可以用.off("click.myPlugin")方法或.off("click.simple")方法删除,而不会干扰其它附加到此元素的点击处理函数。命名空间类似于CSS类,在于它们没有层级;只需要匹配一个名称。用下划线开始的命名空间为jQuery保留,供jQuery使用。

.on()的第二种形式中,events是一个扁平对象。键是字符串,与events参数的形式相同,带有空格分隔的事件类型名称以及可选的命名空间。每个键的值是一个函数(或者false值),用作handler,代替用于此方法的最后一个参数。另一方面,这两种形式在它们的行为上是相同的,如下所述。

直接事件和委托事件

大多数浏览器事件的冒泡,或者传播,都是从文档树中事件发生的最深的最内部的元素(event target)向上传播到<body>和document元素。在Internet Explorer 8以及更低的版本中,一些事件,譬如change事件和submit不会原生冒泡,但是jQuery修补了这些让它们泡冒,创建了一致的跨浏览器行为。

如果省略了selector或者设置为null,事件处理函数被称为直接直接绑定。每当在选中的元素上发生事件时,就调用此处理函数,无论事件是直接发生在元素上,还是从后代(内部)元素冒泡上来的。

如果提供了一个selector,事件处理函数被称为委托。当事件直接发生在绑定的元素上时不会调用,只有发生在匹配此选择器的后代元素上时才调用。jQuery从事件目标向冒泡了事件,直到附加处理函数的元素。

事件处理函数只绑定到目前选中的元素;当你的代码制作对.on()的调用时,这些对象必须已经存在。若要确保元素已经存在,而且可被选中,请在HTML标记中把脚本放在元素后面,或者在一个document ready处理函数内部实施事件绑定。替代方案是,使用委托事件来附加事件处理函数。

委托事件具有优点是,它们可以处理来自以后添加到文档中的后代元素的事件。通过取得一个保证在委托事件附加时已经存在的元素,你可以使用委托事件来避免需要频繁附加和删除事件处理函数。此元素可以是MVC设计中的一个视图的容器元素,或者是document,如果事件处理函数想要监视文档中所有的冒泡事件。在载入任何其它HTML之前,在文档的head中,document元素是可用的,所以它可以安全地附加事件,而不需要等待文档就绪。

除了它们能够处理还未创建的后代元素上的事件,委托事件别的优点是当必须监视很多元素时,它们的潜在开销要低得多。在一个带有1000行的表格中,此示例附加对1000个元素附加了处理函数:

1
2
3
$( "#dataTable tbody tr" ).on( "click", function() {
console.log( $( this ).text() );
});

一个事件委托实现方法把事件处理函数只附加到一个元素,即tbody,然后事件可以只需要冒泡到一级(从点击过的tr冒泡到tbody):

1
2
3
$( "#dataTable tbody" ).on( "click", "tr", function() {
console.log( $( this ).text() );
});

注意:委托事件对SVG不起作用。

事件处理函数和它的环境

handler参数是一个函数(或者是值false,请看下面),是必不可少的,除非你为events参数传递了一个对象。你可以在.on调用的点上提供一个匿名处理函数,如上面的示例所做的,或者声明一个命名函数,然后传递它的名称:

1
2
3
4
function notify() {
alert( "clicked" );
}
$( "button" ).on( "click", notify );

当浏览器触发一个事件或其它JavaScript调用jQuery的.trigger()方法时,jQuery传给处理函数一个Event对象,它可以用来分析和改变事件的状态。此对象是一个浏览器提供的数据的规范化子集,浏览器的未经修改的原生事件对象在event.originalEvent中可用。例如,event.type包含了一个事件名称(例如,“resize”)而event.target指示事件发生的最深(最内部)的元素。

默认情况下,大多数事件从原始事件目标冒泡到document元素。沿着这一路的每个元素,jQuery调用任何已经附加的匹配的事件处理函数。通过调用event.stopPropagation(),处理函数可以防止事件进一步沿着文档树向上冒泡(从而防止那些元素上的处理函数运行)。然而,任何其它已经附加到当前元素上的处理函数还将运行。为了防止那,请调用event.stopImmediatePropagation()。(绑定到一个元素上的事件处理函数会按照绑定它们的顺序调用。)

类似地,处理函数可以调用event.preventDefault()来防止撤销浏览器针对此事件的任何默认操作;例如,在click事件上的默认操作是打开一个链接。并不是所有的浏览器事件都具有默认操作,并不是所有的默认操作都可以被撤销。请参阅W3C Events 规范文档以了解详情。

从一个事件处理函数上返回false将自动调用event.stopPropagation()event.preventDefault()。也可以向handler传递一个false值,作为function(){ return false; }的简写。所以,$( "a.disabled" ).on( "click", false );向所有的带有类“disabled”的链接附加了一个事件处理函数,防止在点击那些链接时打开那些链接,也阻止了事件冒泡。

当jQuery调用处理函数时,this关键字是对事件已经发送到的元素的一个引用;对于直接绑定事件,它是事件附加到的元素,对于委托事件,它是匹配selector的元素。(请注意,this可能不等于event.target,如果事件是从一个后代元素冒泡上来的)。若要根据元素创建一个jQuery对象,从而可以对它使用jQuery方法,请用$( this )

向处理函数传递数据

如果给.on()方法提供了data参数,而且它不是nullundefined,每当触发事件时,它会在event.data中传递给处理函数。data参数可以是任何类型,但是如果使用了一个字符串,则必须提供selector,或者明确把selector指定为null,从而data不会被误当成selector。最佳实践是使用扁平对象,从而可以传入多个值作为属性。

自从jQuery 1.4,可以多次把同一个事件处理函数绑定到一个元素。当使用到event.data功能时,它特别有用。例如:

1
2
3
4
5
6
7
8
9
function greet( event ) {
alert( "Hello " + event.data.name );
}
$( "button" ).on( "click", {
name: "Karl"
}, greet );
$( "button" ).on( "click", {
name: "Addy"
}, greet );

上面的代码,当点击按钮时,将生成两个不同的警告消息。

此外,作为data参数提供给.on()方法的替代方案,你还可以利用.trigger()方法或.triggerHandler()方法的第二个参数把数据传递给事件处理函数。通过这种方法提供给事件处理函数成为Event对象后面的那些参数。如果一个数组传递给.trigger().triggerHandler()的第二个参数,数组中的每个元素都将出现在事件处理函数中,作为独立的参数。

事件性能

在大多数情况下,一个事件,譬如click,出现得很稀少,性能不是一个重大问题。然而,高频率事件,譬如mousemovescroll每秒将引发几十次,那样的话,明智地使用事件变得很重要。通过减少处理函数本身要做的工作量,缓存处理函数需要的信息而不是重复计算它,或者利用setTimeout限制的页面更新的实际次数,可以提升性能。

在接近文档树的顶部的地方附加很多委托事件处理函数,也会降低性能。每当事件发生时,jQuery必须将从事件目标开始到文档顶部的路径中每一个元素与所有附加事件的选择器作比较。为了更好的性能,请尽可能在接近目标元素的地方委托事件。在大文档中,避免滥用documentdocument.body来委托事件。

jQuery可以快速处理tag#id.class形式的简单选择器,当选择器用来筛选委托事件时。所以,"#myForm""a.external""button"都是快速选择器。使用更复杂的选择器委托事件,特别是用层级选择器,可能很耗费时间——然而对大多数应用程序来说,它们依然足够快。通常可以通过把处理函数附加到更合适的文档位点上,来避免层级选择器。例如,不要用$( "body" ).on( "click", "#commentForm .addNew", addComment ),请用$( "#commentForm" ).on( "click", ".addNew", addComment )

额外的注意

对于某些事件,有自己的简写方法,譬如.click()可被用来附加或触发事件处理函数。欲得简写方法的完整列表,请参阅events 类别

"hover"在jQuery 1.8中被淘汰,在jQuery 1.9中被删除,它被用作字符串"mouseenter mouseleave"的简写。它为那两种事件附加了单个事件处理函数,处理函数必须检查event.type来确定事件是mouseenter还是mouseleave。请不要将“hover”伪事件名称与.hover()方法搞混,.hover()方法接受一个或两个函数。

jQuery的事件系统需要DOM允许通过元素上的属性附加数据,从而可以跟踪和递送事件。objectembedapplet元素不能附加数据,因此不能给它们绑定jQuery事件。

W3C指定的focus事件和blur事件不能冒泡,但是jQuery定义了跨浏览器的focusin事件和focusout事件,可以冒泡。当focus事件和blur事件用来附加委托事件处理函数时,jQuery映射了事件名,分别把它们递送为focusinfocusout。为了一致性和明确性,请使用可冒泡的事件类型名称。

在所有浏览器中,load事件、scroll事件和error事件(例如,在<img>元素上)都不能冒泡。在Internet Explorer 8及更低版本中,paste事件和reset事件也不能冒泡。这样的事件不支持使用委托,但是当处理函数直接附加到生成事件的元素上时,可以用它们。

window对象上的error事件使用非标准的参数,并按惯例返回值,所以jQuery不支持它。请把处理函数直接赋值给window.onerror属性。

当事件最早被递送时,设置了针对元素的处理函数列表。在当前元素上添加或删除事件处理函数不能生效,直到下一次处理事件时才能生效。若要防止一个元素上事件处理函数在事件处理函数内部被进一步执行,请调用event.stopImmediatePropagation()。此行为违反了W3C 事件规范文档。若要更好地理解这种情况,请考虑下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
var $test = $( "#test" );
function handler1() {
console.log( "handler1" );
$test.off( "click", handler2 );
}
function handler2() {
console.log( "handler2" );
}
$test.on( "click", handler1 );
$test.on( "click", handler2 );

在上面的代码中,第一次无论如何都将执行handler2,哪怕已经用.off()删除了它。然而,在下次触发click事件时,不会再执行此处理函数。

示例:

当文本被点击时,在警告消息中显示段落的文本:

1
2
3
$( "p" ).on( "click", function() {
alert( $( this ).text() );
});

向事件处理函数传递数据,在这里用名称指定它:

1
2
3
4
function myHandler( event ) {
alert( event.data.foo );
}
$( "p" ).on( "click", { foo: "bar" }, myHandler );

通过返回false来取消表单提交操作,并阻止事件冒泡:

1
$( "form" ).on( "submit", false );

利用.preventDefault()只取消默认行为。

1
2
3
$( "form" ).on( "submit", function( event ) {
event.preventDefault();
});

阻止submit事件向上冒泡,但是不阻止表单提交,请使用.stopPropagation()

1
2
3
$( "form" ).on( "submit", function( event ) {
event.stopPropagation();
});

使用.trigger()的第二个参数向事件处理函数传递数据。

1
2
3
4
$( "div" ).on( "click", function( event, person ) {
alert( "Hello, " + person.name );
});
$( "div" ).trigger( "click", { name: "Jim" } );

使用.trigger()的第二个参数,向事件处理函数传递数据的数组。

1
2
3
4
$( "div" ).on( "click", function( event, salutation, name ) {
alert( salutation + ", " + name );
});
$( "div" ).trigger( "click", [ "Goodbye", "Jim" ] );

附加并触发自定义(非浏览器)事件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>on demo</title>
<style>
p {
color: red;
}
span {
color: blue;
}
</style>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<p>Has an attached custom event.</p>
<button>Trigger custom event</button>
<span style="display:none;"></span>
<script>
$( "p" ).on( "myCustomEvent", function( event, myName ) {
$( this ).text( myName + ", hi there!" );
$( "span" )
.stop()
.css( "opacity", 1 )
.text( "myName = " + myName )
.fadeIn( 30 )
.fadeOut( 1000 );
});
$( "button" ).click(function () {
$( "p" ).trigger( "myCustomEvent", [ "John" ] );
});
</script>
</body>
</html>

演示:

使用扁平对象同步附加多个事件处理函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>on demo</title>
<style>
.test {
color: #000;
padding: .5em;
border: 1px solid #444;
}
.active {
color: #900;
}
.inside {
background-color: aqua;
}
</style>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<div class="test">test div</div>
<script>
$( "div.test" ).on({
click: function() {
$( this ).toggleClass( "active" );
}, mouseenter: function() {
$( this ).addClass( "inside" );
}, mouseleave: function() {
$( this ).removeClass( "inside" );
}
});
</script>
</body>
</html>

演示:

点击任何段落,以在它后面添加另一个段落。请注意,.on()允许点击事件在任何段落上——哪怕是新段落上——因为事件是由始终在场的body元素处理的,在事件冒泡到body之后处理它。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>on demo</title>
<style>
p {
background: yellow;
font-weight: bold;
cursor: pointer;
padding: 5px;
}
p.over {
background: #ccc;
}
span {
color: red;
}
</style>
<script src="https://code.jquery.com/jquery-1.10.2.js"></script>
</head>
<body>
<p>Click me!</p>
<span></span>
<script>
var count = 0;
$( "body" ).on( "click", "p", function() {
$( this ).after( "<p>Another paragraph! " + (++count) + "</p>" );
});
</script>
</body>
</html>

演示:

每当段落被点击时,在警告框中显示每个段落的文本。

1
2
3
$( "body" ).on( "click", "p", function() {
alert( $( this ).text() );
});

使用.preventDefault()方法撤销链接的默认动作。

1
2
3
$( "body" ).on( "click", "a", function( event ) {
event.preventDefault();
});

对同一个元素附加多个事件——一个在mouseenter上,另一个在mouseleave上:

1
2
3
$( "#cart" ).on( "mouseenter mouseleave", function( event ) {
$( this ).toggleClass( "active" );
});