第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > Event 系列: jquery event 源码

Event 系列: jquery event 源码

时间:2019-07-21 01:33:37

相关推荐

Event 系列: jquery event 源码

/* *author:prk *date:-08-17 *comment:analyseofjqueryevent * */jQuery.event={ //add事件到一个元素上。 add:function(elem,types,handler,data){if(elem.nodeType==3||elem.nodeType==8)//空白节点或注释return; //IE不能传入window,先复制一下。if(jQuery.browser.msie&&elem.setInterval) elem=window; //为handler分配一个全局唯一的Idif(!handler.guid) handler.guid=this.guid++; //把data附到handler.data中if(data!=undefined){ varfn=handler; handler=this.proxy(fn,function(){//唯一Id,wrap原始handlerFnreturnfn.apply(this,arguments); }); handler.data=data; } //初始化元素的events。如果没有取到events中值,就初始化data:{} varevents=jQuery.data(elem,"events") ||jQuery.data(elem,"events",{}), //如果没有取到handle中值,就初始化data:function(){....} handle=jQuery.data(elem,"handle") ||jQuery.data(elem,"handle",function(){ //处理一个触发器的第二个事件和当page已经unload之后调用一个事件。if(typeofjQuery!="undefined"&&!jQuery.event.triggered)returnjQuery.event.handle.apply(//arguments.callee.elem=handle.elem arguments.callee.elem,arguments); }); //增加elem做为handle属性,防止IE由于没有本地Event而内存泄露。 handle.elem=elem; //处理采用空格分隔多个事件名,如jQuery(...).bind("mouseovermouseout",fn); jQuery.each(types.split(/\s+/),function(index,type){ //命名空间的事件,一般不会用到。 varparts=type.split("."); type=parts[0]; handler.type=parts[1]; //捆绑到本元素type事件的所有处理函数 varhandlers=events[type];if(!handlers){//没有找到处理函数列表就初始化事件队列 handlers=events[type]={}; //如果type不是ready,或ready的setup执行返回falseif(!jQuery.event.special[type] ||jQuery.event.special[type].setup .call(elem,data)===false){ //调用系统的事件函数来注册事件if(elem.addEventListener)//FF elem.addEventListener(type,handle,false);elseif(elem.attachEvent)//IE elem.attachEvent("on"+type,handle); } } //把处理器的id和handler形式属性对的形式保存在handlers列表中, //也存在events[type][handler.guid]中。 handlers[handler.guid]=handler; //全局缓存这个事件的使用标识 jQuery.event.global[type]=true; }); //防止IE内存泄露。 elem=null; }, guid:1, global:{}, //从元素中remove一个事件 remove:function(elem,types,handler){if(elem.nodeType==3||elem.nodeType==8)return; //取出元素的events中Fn列表 varevents=jQuery.data(elem,"events"),ret,index;if(events){ //remove所有的该元素的事件.是命名空间的处理if(types==undefined ||(typeoftypes=="string"&&types.charAt(0)=="."))for(vartypeinevents)this.remove(elem,type+(types||""));else{ //types,handler参数采用{type:xxx,handler:yyy}形式if(types.type){ handler=types.handler; types=types.type; } //处理采用空格分隔多个事件名jQuery(...).unbind("mouseovermouseout",fn); jQuery .each(types.split(/\s+/),function(index,type){ //命名空间的事件,一般不会用到。 varparts=type.split("."); type=parts[0];if(events[type]){//事件名找到if(handler)//handler传入,就remove事件名的这个处理函数 deleteevents[type][handler.guid];//guid的作用else//remove这个事件的所有处理函数,带有命名空间的处理for(handlerinevents[type])if(!parts[1] ||events[type][handler].type==parts[1]) deleteevents[type][handler]; //如果没有该事件的处理函数存在,就remove事件名for(retinevents[type])//看看有没有?break;if(!ret){//没有if(!jQuery.event.special[type]//不是ready ||jQuery.event.special[type].teardown .call(elem)===false){//type不等于readyif(elem.removeEventListener)//在浏览器中remove事件名 elem.removeEventListener(type, jQuery.data(elem, "handle"),false);elseif(elem.detachEvent) elem.detachEvent("on"+type, jQuery.data(elem, "handle")); } ret=null; deleteevents[type];//在缓存中除去。 } } }); } //不再使用,除去expandofor(retinevents)break;if(!ret){ varhandle=jQuery.data(elem,"handle");if(handle) handle.elem=null; jQuery.removeData(elem,"events"); jQuery.removeData(elem,"handle"); } } }, trigger:function(type,data,elem,donative,extra){ data=jQuery.makeArray(data);if(type.indexOf("!")>=0){//支持!的not的操作如!click,除click之后的所有 type=type.slice(0,-1);//除最后一个字符? varexclusive=true; }if(!elem){//处理全局的fire事件if(this.global[type]) jQuery.each(jQuery.cache,function(){ //从cache中找到所有注册该事件的元素,触发改事件的处理函数if(this.events&&this.events[type]) jQuery.event.trigger(type,data,this.handle.elem); }); }else{//处理单个元素事件的fire事件if(elem.nodeType==3||elem.nodeType==8)returnundefined; varval,ret,fn=jQuery.isFunction(elem[type]||null), //我们是否要提交一个伪造的事件? event=!data[0]||!data[0].preventDefault; //构建伪造的事件。if(event){ data.unshift({//存到数组中的第一个 type:type, target:elem, preventDefault:function(){ }, stopPropagation:function(){ }, timeStamp:now() }); data[0][expando]=true;//不需要修正伪造事件 } //防止事件名出错 data[0].type=type;if(exclusive) data[0].exclusive=true; //触发事件 varhandle=jQuery.data(elem,"handle");if(handle) val=handle.apply(elem,data); //Handletriggeringnative.onfoohandlers(andonlinkssincewe //don'tcall.click()forlinks) //处理触发.onfoo这样的本地处理方法,但是是对于links's.click()不触发if((!fn||(jQuery.nodeName(elem,'a')&&type=="click")) &&elem["on"+type]&&elem["on"+type].apply(elem,data)===false) val=false; //Extrafunctionsdon'tgetthecustomeventobjectif(event) data.shift(); //处理触发extra事件if(extra&&jQuery.isFunction(extra)){ //执行extra,同时把结果存到data中。 ret=extra.apply(elem,val==null?data:data.concat(val)); //ifanythingisreturned,giveitprecedenceandhaveit //overwritethepreviousvalueif(ret!==undefined) val=ret; } //触发本地事件if(fn&&donative!==false&&val!==false&&!(jQuery.nodeName(elem,'a')&&type=="click")){this.triggered=true;try{ elem[type](); //对于一些hidden的元素,IE会报错 }catch(e){ } }this.triggered=false; }returnval; }, handle:function(event){ //返回undefinedorfalse varval,ret,namespace,all,handlers; event=arguments[0]=jQuery.event.fix(event||window.event); //命名空间处理 namespace=event.type.split("."); event.type=namespace[0]; namespace=namespace[1]; //all=true表明任何handler all=!namespace&&!event.exclusive; //找到元素的events中缓存的事件名的处理函数列表 handlers=(jQuery.data(this,"events")||{})[event.type];for(varjinhandlers){//每个处理函数执行 varhandler=handlers[j]; //Filterthefunctionsbyclassif(all||handler.type==namespace){ //传入引用,为了之后删除它们 event.handler=handler; event.data=handler.data; ret=handler.apply(this,arguments);//执行事件处理函数if(val!==false) val=ret;//只要有一个处理函数返回false,本函数就返回false.if(ret===false){//不执行浏览器默认的动作 event.preventDefault(); event.stopPropagation(); } } }returnval; }, props:"altKeyattrChangeattrNamebubblesbuttoncancelablecharCodeclientX"+"clientYctrlKeycurrentTargetdatadetaileventPhasefromElementhandlerkeyCode"+"metaKeynewValueoriginalTargetpageXpageYprevValuerelatedNoderelatedTargetscreenX"+"screenYshiftKeysrcElementtargettimeStamptoElementtypeviewwheelDeltawhich".split(""), //对事件进行包裹。 fix:function(event){if(event[expando]==true)//表明事件已经包裹过returnevent; //保存原始event,同时clone一个。 varoriginalEvent=event; event={ originalEvent:originalEvent };for(vari=this.props.length,prop;i;){ prop=this.props[--i]; event[prop]=originalEvent[prop]; } event[expando]=true; //加上preventDefaultandstopPropagation,在clone不会运行 event.preventDefault=function(){ //在原始事件上运行if(originalEvent.preventDefault) originalEvent.preventDefault(); originalEvent.returnValue=false; }; event.stopPropagation=function(){ //在原始事件上运行if(originalEvent.stopPropagation) originalEvent.stopPropagation(); originalEvent.cancelBubble=true; }; //修正timeStamp event.timeStamp=event.timeStamp||now(); //修正targetif(!event.target) event.target=event.srcElement||document;if(event.target.nodeType==3)//文本节点是父节点。 event.target=event.target.parentNode; //relatedTargetif(!event.relatedTarget&&event.fromElement) event.relatedTarget=event.fromElement==event.target ?event.toElement :event.fromElement; //CalculatepageX/YifmissingandclientX/Yavailableif(event.pageX==null&&event.clientX!=null){ vardoc=document.documentElement,body=document.body; event.pageX=event.clientX +(doc&&doc.scrollLeft||body&&body.scrollLeft||0) -(doc.clientLeft||0); event.pageY=event.clientY +(doc&&doc.scrollTop||body&&body.scrollTop||0) -(doc.clientTop||0); } //Addwhichforkeyeventsif(!event.which &&((event.charCode||event.charCode===0) ?event.charCode :event.keyCode)) event.which=event.charCode||event.keyCode; //AddmetaKeytonon-Macbrowsers(usectrlforPC'sandMetaforMacs)if(!event.metaKey&&event.ctrlKey) event.metaKey=event.ctrlKey; //Addwhichforclick:1==left;2==middle;3==right //Note:buttonisnotnormalized,sodon'tuseitif(!event.which&&event.button) event.which=(event.button&1?1:(event.button&2?3:(event.button&4?2:0)));returnevent; }, proxy:function(fn,proxy){ //作用就是分配全局guid. proxy.guid=fn.guid=fn.guid||proxy.guid||this.guid++;returnproxy; }, special:{ ready:{ //Makesurethereadyeventissetup setup:bindReady, teardown:function(){ } } } };if(!jQuery.browser.msie){ //Checksifaneventhappenedonanelementwithinanotherelement //UsedinjQuery.event.special.mouseenterandmouseleavehandlers varwithinElement=function(event){ //Checkifmouse(over|out)arestillwithinthesameparentelement varparent=event.relatedTarget; //Traverseupthetreewhile(parent&&parent!=this)try{ parent=parent.parentNode; }catch(e){ parent=this; }if(parent!=this){ //setthecorrecteventtype event.type=event.data; //handleeventifweactuallyjustmousedontoanonsub-element jQuery.event.handle.apply(this,arguments); } }; jQuery.each({ mouseover:'mouseenter', mouseout:'mouseleave'},function(orig,fix){ jQuery.event.special[fix]={ setup:function(){ jQuery.event.add(this,orig,withinElement,fix); }, teardown:function(){ jQuery.event.remove(this,orig,withinElement); } }; }); } jQuery.fn.extend({ bind:function(type,data,fn){returntype=="unload"?this.one(type,data,fn):this.each(function(){//fn||data,fn&&data实现了data参数可有可无 jQuery.event.add(this,type,fn||data,fn&&data); }); }, //为每一个匹配元素的特定事件(像click)绑定一个一次性的事件处理函数。 //在每个对象上,这个事件处理函数只会被执行一次。其他规则与bind()函数相同。 //这个事件处理函数会接收到一个事件对象,可以通过它来阻止(浏览器)默认的行为。 //如果既想取消默认的行为,又想阻止事件起泡,这个事件处理函数必须返回false。 one:function(type,data,fn){ varone=jQuery.event.proxy(fn||data,function(event){ jQuery(this).unbind(event,one);return(fn||data).apply(this,arguments);//this-->当前的元素 });returnthis.each(function(){ jQuery.event.add(this,type,one,fn&&data); }); }, //bind()的反向操作,从每一个匹配的元素中删除绑定的事件。 //如果没有参数,则删除所有绑定的事件。 //你可以将你用bind()注册的自定义事件取消绑定。 //I如果提供了事件类型作为参数,则只删除该类型的绑定事件。 //如果把在绑定时传递的处理函数作为第二个参数,则只有这个特定的事件处理函数会被删除。 unbind:function(type,fn){returnthis.each(function(){ jQuery.event.remove(this,type,fn); }); }, trigger:function(type,data,fn){returnthis.each(function(){ jQuery.event.trigger(type,data,this,true,fn); }); }, //这个特别的方法将会触发指定的事件类型上所有绑定的处理函数。但不会执行浏览器默认动作. triggerHandler:function(type,data,fn){returnthis[0] &&jQuery.event.trigger(type,data,this[0],false,fn); }, //每次点击后依次调用函数。 toggle:function(fn){ varargs=arguments,i=1;while(i<args.length)//每个函数分配GUID jQuery.event.proxy(fn,args[i++]);returnthis.click(jQuery.event .proxy(fn,function(event){//分配GUIDthis.lastToggle=(this.lastToggle||0)%i;//上一个函数 event.preventDefault();//阻止缺省动作 //执行参数中的第几个函数,apply可以采用array-like的参数 //Withapply,youcanuseanarrayliteral, //forexample,fun.apply(this,[name,value]), //oranArrayobject,forexample,fun.apply(this,newArray(name,value)).returnargs[this.lastToggle++].apply(this, arguments)||false; })); }, //一个模仿悬停事件(鼠标移动到一个对象上面及移出这个对象)的方法。 //这是一个自定义的方法,它为频繁使用的任务提供了一种“保持在其中”的状态。 //当鼠标移动到一个匹配的元素上面时,会触发指定的第一个函数。当鼠标移出这个元素时, //会触发指定的第二个函数。而且,会伴随着对鼠标是否仍然处在特定元素中的检测(例如,处在div中的图像), //如果是,则会继续保持“悬停”状态,而不触发移出事件(修正了使用mouseout事件的一个常见错误)。 hover:function(fnOver,fnOut){returnthis.bind('mouseenter',fnOver).bind('mouseleave',fnOut); }, //domready时执行fn ready:function(fn){ bindReady();//注册监听if(jQuery.isReady)//ready就运行 fn.call(document,jQuery);else//增加这个函数到queue中。可见支持无数的ready的调用。 jQuery.readyList.push(function(){returnfn.call(this,jQuery); });returnthis; } }); jQuery.extend({ isReady:false, readyList:[], //HandlewhentheDOMisready ready:function(){if(!jQuery.isReady){ jQuery.isReady=true;if(jQuery.readyList){ jQuery.each(jQuery.readyList,function(){this.call(document); }); jQuery.readyList=null; } jQuery(document).triggerHandler("ready"); } } }); varreadyBound=false; functionbindReady(){if(readyBound)return; readyBound=true; //Mozilla,Opera,webkitnightlies支持DOMContentLoaded事件if(document.addEventListener&&!jQuery.browser.opera) //当DOMContentLoaded事件触发时就运行jQuery.ready document.addEventListener("DOMContentLoaded",jQuery.ready,false); //IE或不是frame的windowif(jQuery.browser.msie&&window==top) (function(){if(jQuery.isReady)return;try{ //在ondocumentready之前,一直都会抛出异常 ///IEContentLoaded/ document.documentElement.doScroll("left"); }catch(error){ //一直运行bindReady()(=arguments.callee) setTimeout(arguments.callee,0);return; } jQuery.ready();//documentready就运行jQuery.ready })();if(jQuery.browser.opera) document.addEventListener("DOMContentLoaded",function(){if(jQuery.isReady)return; //只有styleSheets完全enable时,才是完全的load,其实还有picfor(vari=0;i<document.styleSheets.length;i++)if(document.styleSheets[i].disabled){//通过styleSheets来判断 setTimeout(arguments.callee,0);return; } jQuery.ready(); },false);if(jQuery.browser.safari){ varnumStyles; (function(){if(jQuery.isReady)return; //首先得得到readyState=loaded或=completeif(document.readyState!="loaded"&&document.readyState!="complete"){ setTimeout(arguments.callee,0);return; } //取得style的length,比较它们之间的长度,看看是不是完成loadedif(numStyles===undefined) numStyles=jQuery("style,link[rel=stylesheet]").length;if(document.styleSheets.length!=numStyles){ setTimeout(arguments.callee,0);return; } jQuery.ready(); })(); } //最后只能依赖于window.load. jQuery.event.add(window,"load",jQuery.ready); } //为jquery对象增加常用的事件方法 jQuery .each( ("blur,focus,load,resize,scroll,unload,click,dblclick,"+"mousedown,mouseup,mousemove,mouseover,mouseout,change,select,"+"submit,keydown,keypress,keyup,error") .split(","),function(i,name){ jQuery.fn[name]=function(fn){returnfn?this.bind(name,fn):this.trigger(name); }; }); //PreventmemoryleaksinIE //Andpreventerrorsonrefreshwitheventslikemouseoverinotherbrowsers //Windowisn'tincludedsoasnottounbindexistingunloadevents jQuery(window).bind('unload',function(){for(varidinjQuery.cache) //Skipthewindowif(id!=1&&jQuery.cache[id].handle) jQuery.event.remove(jQuery.cache[id].handle.elem); });

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。