测试代码1:
var data = { id: 5, name: "张三" }; var events = { "mouseenter": function(event){ $(this).html( "你好," + event.data.name + "!"); }, "mouseleave": function(event){ $(this).html( "再见!"); } }; //为n5绑定mouseenter mouseleave两个事件,并为其传入附加数据data $("body").on(events, "#n5", data); });测试代码2:
var eventsMap = { "mouseenter": function(event){ $(this).html( "Hello!"); }, "mouseleave": function(event){ $(this).html( "Bye!"); } }; //为n5绑定mouseenter mouseleave两个事件 $("#n5").one( eventsMap ); alert(typeof eventsMap);//eventsMap是object测试代码3:
$("div").on("click", "p", function(){ // 这里的this指向触发点击事件的p元素(Element) alert( $(this).text() ); }); 这种调用逻辑的时候:第一个参数是types,第二个参数是selector,第三个参数是fnreturnFalse函数:
function returnFalse() { return false; }测试代码4:
<input id="btn" type="button" value="点击" /> $("#btn").bind("click", function(){ alert("我是前面已经绑定的事件!"); }); // 只有第一次点击时,执行该事件处理函数 // 执行后one()会立即移除绑定的事件处理函数 $("#btn").one("click", function(){ alert("只弹出一次提示框!"); });测试代码5:
$(function() { alert(jQuery.guid);//打印1 $("input").bind("click",function() { alert("点击!"); }) alert(jQuery.guid);//打印2 }) jQuery中为每一个函数设置一个全局的guid属性,该guid用于事件模块和缓存模块测试uuid和guid:
<html> <head> <script type="text/javascript" src="/jquery/jquery.js"></script> <script type="text/javascript"> $(function() { alert(jQuery.guid);//默认初始值是1 $("input").bind("click",function() { alert("点击!"); }) alert(jQuery.guid);//事件处理或者缓存系统会把guid++,所以是2 function T() { alert("我测试你在不"); } $("input").bind("click",T) alert(jQuery.guid);//再次绑定事件以后guid++变成3,所以全局jQuery.guid是不断自增的! alert(T.guid);//但是对于这个T函数来说,他是第二个函数,所以他的guid只是2 //下面为button添加数据测试uuid $("button").data("sex","male"); alert("data添加数据测试uuid->"+jQuery.uuid);//uuid默认是0,采取++index前增长策略 alert("data添加数据测试jQuery.expando->"+jQuery.expando); alert("data添加数据测试id->"+$("input")[0][jQuery.expando]);//记住这里是DOM对象! /*Query.data( elem, name, data, pvt) elem[ internalKey ] = id = ++jQuery.uuid; jQuery.event.add: function( elem, types, handler, data, selector ) handler.guid = jQuery.guid++; (每次绑定一个事件把事件处理函数的guid赋值,赋值为全局的guid的值。但是每次绑定guid自增,所以函数用到的只是前面的一个guid,这主要来源于guid++是赋值后增长的!所以T.guid===2不是3) }) </script> </head> <body> <p>段落文本内容 <input type="button" value="点击" /> </p> </body> </html>每次绑定事件都会把guid自增,每次存储数据会把uuid自增!
fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; 对于fn来说,添加事件以后传入该函数一个[object MouseEvent]对象,他做的事情有两件:(1)把这个MouseEvent事件通过jQuery().off移除 (2)把上次的one函数传递进来的函数通过闭包引用并且执行! 实例代码:(第一次点击弹出两个对话框,以后弹出一次!,因为click事件已经被移除了!) <input id="btn" type="button" value="点击" /> $("#btn").bind("click", function(){ alert("我是前面已经绑定的事件!"); }); // 只有第一次点击时,执行该事件处理函数·1 // 执行后one()会立即移除绑定的事件处理函数 $("#btn").one("click", function(){ alert("只弹出一次提示框!"); });下面开始on方法的源码分析:
on: function( types, selector, data, fn, /*INTERNAL*/ one ) { var type, origFn; // Types can be a map of types/handlers //如果第一个types的对象是object类型,见代码1 if ( typeof types === "object" ) { // ( types-Object, selector, data ) //如果第二个参数不是string,那么调用方式就是$("p").on(typeObject,dataObject)也就是第一个参数是type对象,第二个参数是数据对象 if ( typeof selector !== "string" ) { // ( types-Object, data ) data = data || selector; selector = undefined; } //获取types封装的每一个type对象 for ( type in types ) { //继续逐个绑定到选择器选择的对象上面去。也就是虽然事件类型是一个object对象,但是还是要逐个绑定事件 //type是"mouseenter",但是types[type]就是function对象 this.on( type, selector, data, types[ type ], one ); } return this; } //如果第一个参数不是object类型,同时第三个和第四个参数data和fn同时是null,因为undefined==null恒成立! //这个if语句的调用逻辑是:$("p").on("click",function(){})也就是只有两个参数,这种调用方式第二个参数是fn //第一个是types,data和selector是undefined。on: function( types, selector, data, fn, /*INTERNAL*/ one ) if ( data == null && fn == null ) { // ( types, fn ) //把selector赋值给fn,记住韦恩图的逻辑! fn = selector; data = selector = undefined; } else if ( fn == null ) {//仅仅fn为null,data不是null,function( types, selector, data, fn, /*INTERNAL*/ one ) if ( typeof selector === "string" ) { // ( types, selector, fn ) fn = data; data = undefined; } else { // ( types, data, fn )调用方式 //function( types, selector, data, fn, /*INTERNAL*/ one ) fn = data; data = selector; selector = undefined; } } //如果第四个参数是false,那么就把事件触发时候的回调函数设为returnFalse函数! if ( fn === false ) { fn = returnFalse; } else if ( !fn ) { return this; } //如果传入了最后一个参数,同时设置为1,在下面的one()函数中会被调用 if ( one === 1 ) { //保存原来的传递过来的事件函数 //把one调用的函数作为局部变量保存下来 origFn = fn; //对传进来的fn重新赋值,这个函数是一个全新的函数,这个函数首先移除相应的事件,移除以后还要做一件事就是把one传递进来的函数执行 //一次 fn = function( event ) { // Can use an empty set, since event contains the info jQuery().off( event ); return origFn.apply( this, arguments ); }; // Use same guid so caller can remove using origFn //设置新函数的guid,如果one传进来的函数已经有了guid,那么直接赋值,否则从jQuery获取 fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); } //jQuery.event.add传入参数,第一个参数是遍历出来的jQuery对象转化成的DOM对象,即$("p")[i] //第二个参数是类型,第三个参数回调函数,第四个参数是传递的额外数据,最后一个是选择器 return this.each( function() { //把这个新函数添加到相应的this对象上去,this是jQuery对象 jQuery.event.add( this, types, fn, data, selector ); }); },总结:
on方法其实就是对每一个调用对象单独调用jQuery.event.add方法进行事件绑定!但是因为one方法也是调用的是on方法,所以最后一个参数one就是表示是否是one方法,如果是,该方法就是首先把该事件移除,同时为add方法传入的新的函数句柄,该新的函数通过闭包的形式访问原始的函数!