on()

在选定的元素上绑定一个或多个事件处理函数。

.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
.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()

on() 可以绑定的事件

表单事件 blur focus focusin focusout change select submit
浏览器事件 resize scroll
鼠标事件 click dblclick contextmenu
键盘事件 mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave keydown keypress keyup
自定义 事件名称和命名空间

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 参数,但是该值并不是方法中的最后一个参数。在其它方面,这两种形式在下面描述的内容中其行为都是相同的。如下所述。

Direct and delegated events(直接和委托的事件)

大多数浏览器事件 冒泡 ,或者 传播 ,都是由内到外的,从在文档最深处的元素( 事件目标 event target )开始,一路传递到body和 document 元素。(注:事件冒泡简单的说就是,在冒泡路径上所有绑定了相同事件类型的元素上都会触发这些类型的事件。)在Internet Explorer 8和更低,一些事件,如 change submit 本身不冒泡,但 jQuery 为了跨浏览器一致性, jQuery 在这些事件上模拟了冒泡行为。

如果省略 selector 或者是null,那么事件处理程序被称为 直接事件 或者 直接绑定事件 。每次选中的元素触发事件时,就会执行处理程序,不管它直接绑定在元素上,还是从后代(内部)元素冒泡到该元素的

当提供 selector 参数时,事件处理程序是指为 委派 事件(注:通常也有很多人叫它代理事件)。事件不会在直接绑定的元素上触发,但当 selector 参数选择器匹配到后代(内部元素)的时候,事件处理函数才会被触发。jQuery 会从 event target 开始向上层元素(例如,由最内层元素到最外层元素)开始冒泡,并且在传播路径上所有绑定了相同事件的元素若满足匹配的选择器,那么这些元素上的事件也会被触发。

事件处理只能绑定在当前被选中的元素上;而且,在您的代码调用 .on() 的时候,他们必须已经存在。 为了确保目前的元素可以被选择的(注:即,存在),最好将脚本放在元素的HTML标记的后面或者在 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() {
  console.log( $( this ).text() );
});

一个委派事件的方法只在一个元素上绑定一个事件处理程序,下面的代码是绑定在 tbody 元素上,并且事件只会向上冒泡一层(从被点击的 tr tbody ):

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

注意: 委托事件不能用于SVG.

The event handler and its environment(事件处理程序和它的环境)

handler 参数必须是一个函数(或 false 值,见下文),除非你传递一个对象给 events 参数。您可以提供一个匿名处理函数给 .on() 调用,就像上面例子中的用法,或者可以声明一个函数,然后再将该函数名作为参数:

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

当浏览器触发一个事件或其他JavaScript调用的jQuery的 .trigger() 方法,jQuery传递一个 Event 对象给这个处理程序,它可以用来分析和改变事件的状态。这个对象是由浏览器提供一个数据的 标注化子集 ;您需要浏览器自己的未经修改的原始 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)

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 );

按一下按钮时,上面的代码会产生两个不同的警告(alert)。

除了可以向 .on() 方法传入 data 参数外,还可以向.trigger()或.triggerHandler()中传入该参数。这种方式提供数据(Data)被传递给事件处理程序的 Event 对象内,作为进一步的参数。如果传递给 .trigger() .triggerHandler() 的第二个参数是一个数组,数组中的每个元素将作为事件处理程序的单独参数。(注:参见.trigger())

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)

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 属性分配一个处理函数。

当事件被首次触发时,处理函数列表才会被设置到元素上。当前元素上添加或删除事件处理函数不会立即生效,直到下一次的事件被处理。为了避免任何后续事件处理函数在一个元素的事件处理函数中执行,调用 event.stopImmediatePropagation() 这种行为违反了W3C的事件规范。为了更好地了解这种情况下,考虑下面的代码:

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 事件被触发时将不执行。(注:查看代码运行效果:http://jsfiddle.net/feiwen8772/dgxru81d/)

例子

当点击段落时,显示该段落中的文本:

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

向事件处理函数中传入数据,并且在事件处理函数中通过名字来获取传入的数据:

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

取消表单的提交动作,并且通过返回 false 的方法来防止事件冒泡:

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

通过使用 .preventDefault() ,仅取消默认的动作。

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

通过使用 .stopPropagation() ,防止提交事件的冒泡行为,但是并不禁止提交行为。

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

传递一个data数据给 .trigger() 的事件处理程序,作为第二个参数。

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

传递一个数组给 .trigger() 的事件处理程序,作为第二个参数。

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

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

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>on demo</title>
  <style>
  p {
    color: red;
  }
  span {
    color: blue;
  }
  </style>
  <script src="./static/js/jquery-3.5.0.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>

使用对象同时添加多个事件处理函数。

<!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="./static/js/jquery-3.5.0.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 元素上时,就会触发绑定的事件。

<!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="./static/js/jquery-3.5.0.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>

当点击段落时,显示该段落中的文本:

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

使用 preventDefault 方法,取消链接的默认动作。

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

在同一个元素上绑定多个事件,一个 mouseenter mouseleave

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

上篇: ready()

下篇: off()