" /> 波多野一区二区三区在线,黄色片一级免费,国产1区2区3区

一区二区久久-一区二区三区www-一区二区三区久久-一区二区三区久久精品-麻豆国产一区二区在线观看-麻豆国产视频

jQuery源碼分析之Event事件分析

對(duì)于事件的操作無非是addEvent,fireEvent,removeEvent這三個(gè)事 件方法。一般lib都會(huì)對(duì)瀏覽器的提供的函數(shù)做一些擴(kuò)展,解決兼容性內(nèi)存泄漏等問題。第三個(gè)問題就是如何得到domReady的狀態(tài)。
  6.1 event的包裹

  瀏覽器的事件兼容性是一個(gè)令人頭疼的問題。IE的event在是在全局的window下, 而mozilla的event是事件源參數(shù)傳入到回調(diào)函數(shù)中。還有很多的事件處理方式也一樣。

  Jquery提供了一個(gè) event的包裹,這個(gè)相對(duì)于其它的lib提供的有點(diǎn)簡單,但是足夠使用。
復(fù)制代碼 代碼如下:
//對(duì)事件進(jìn)行包裹。
  fix : function(event) {
    if (event[expando] == true) return event;//表明事件已經(jīng)包裹過
    //保存原始event,同時(shí)clone一個(gè)。
    var originalEvent = event;                ①
    event = { originalEvent : originalEvent};
    for (var i = this.props.length, prop;i;) {
       prop = this.props[--i];
      event[prop] = originalEvent[prop];
     }   
    event[expando] = true;   
    //加上preventDefault and stopPropagation,在clone不會(huì)運(yùn)行
    event.preventDefault = function() {          ②
      // 在原始事件上運(yùn)行
      if (originalEvent.preventDefault)
       originalEvent.preventDefault();
       originalEvent.returnValue = false;
    };
    event.stopPropagation = function() {
      // 在原始事件上運(yùn)行
      if (originalEvent.stopPropagation)
        originalEvent.stopPropagation();
      originalEvent.cancelBubble = true;
    };
    // 修正 timeStamp
    event.timeStamp = event.timeStamp || now();
    // 修正target
    if (!event.target)                    ③
      event.target = event.srcElement || document;    
    if (event.target.nodeType == 3)//文本節(jié)點(diǎn)是父節(jié)點(diǎn)。
      event.target = event.target.parentNode;
    // relatedTarget
    if (!event.relatedTarget && event.fromElement)   ④
      event.relatedTarget = event.fromElement == event.target
         ? event.toElement : event.fromElement;
     // Calculate pageX/Y if missing and clientX/Y available
    if (event.pageX == null && event.clientX != null) {?、?
      var doc = 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);
    }
  
    // Add which for key events
   if (!event.which && ((event.charCode || event.charCode === 0) ⑦
            ? event.charCode : event.keyCode))
      event.which = event.charCode || event.keyCode;
  
  // Add metaKey to non-Mac browsers
    if (!event.metaKey && event.ctrlKey)           ?、?
      event.metaKey = event.ctrlKey;
   // Add which for click: 1 == left; 2 == middle; 3 == right
  // Note: button is not normalized, so don't use it
    if (!event.which && event.button)            ?、?
      event.which = (event.button & 1 ? 1 : (event.button & 2
         ? 3 : (event.button & 4 ? 2 : 0)));
    return event;
},


  上面的代碼①處保留原始事件的引用,同時(shí)clone原始事件。在這個(gè)clone的事件上進(jìn)行包裹。②處在原始事件上運(yùn)行 preventDefault 和 stopPropagation兩個(gè)方法達(dá)到是否阻止默認(rèn)的事件動(dòng)作發(fā)生和是否停止冒泡事件事件向上傳遞。

  ?、厶幨切拚齮arget個(gè),IE中采用srcElement,同時(shí)對(duì)于文本節(jié)點(diǎn)事件,應(yīng)該把target傳到其父節(jié)點(diǎn)。

 ?、芴?relatedTarget只是對(duì)于mouseout、mouseover有用。在IE中分成了to和from兩個(gè)Target變量,在mozilla中 沒有分開。為了保證兼容,采用relatedTarget統(tǒng)一起來。

 ?、尢幨沁M(jìn)行event的坐標(biāo)位置。這個(gè)是相對(duì)于page。如果頁面 可以scroll,則要在其client上加上scroll。在IE中還應(yīng)該減去默認(rèn)的2px的body的邊框。

 ?、咛幨前焰I盤事件的按 鍵統(tǒng)一到event.which的屬性上。Ext中的實(shí)現(xiàn)ev.charCode || ev.keyCode || 0; ⑨則是把鼠標(biāo)事件的按鍵統(tǒng)一把event.which上。charCode、ev.keyCode一個(gè)是字符的按鍵,一個(gè)不是字符的按鍵。⑨處采 用&的方式來進(jìn)行兼容性的處理。 Ext 通過下面三行解決兼容問題。

 var btnMap = Ext.isIE ? {1:0,4:1,2:2} : (Ext.isSafari ? {1:0,2:1,3:2} : {0:0,1:1,2:2}); this.button = e.button ? btnMap[e.button] : (e.which ? e.which-1 : -1);

   ①②③④⑤⑥⑦⑧⑨⑩

  6.2 事件的處理

  Jquery提供了一些來進(jìn)行regist,remove,fire事件 的方法。

  6.2.1 Register

  對(duì)于注冊(cè)事件,jquery提供了bind、one、toggle、 hover四種注冊(cè)事件的方法, bind是最基本的方法。One是注冊(cè)只運(yùn)行一次的方法,toggle注冊(cè)交替運(yùn)行的方法。Hover是注冊(cè)鼠標(biāo)浮過的方法。
復(fù)制代碼 代碼如下:
bind : function(type, data, fn) {
  return type == "unload" ? this.one(type, data, fn) : this
    .each(function() {// fn || data, fn && data實(shí)現(xiàn)了data參數(shù)可有可無
         jQuery.event.add(this, type, fn || data, fn && data);
       }); },



  Bind中對(duì)于unload的事件,只能運(yùn)行一次,其它的就采用默認(rèn)的注冊(cè)方式。

// 為每一個(gè)匹配元素的特定事件(像click)綁定一個(gè)一次性的事件處理函數(shù)。
// 在每個(gè)對(duì)象上,這個(gè)事件處理函數(shù)只會(huì)被執(zhí)行一次。其他規(guī)則與bind()函數(shù)相同。
// 這個(gè)事件處理函數(shù)會(huì)接收到一個(gè)事件對(duì)象,可以通過它來阻止(瀏覽器)默認(rèn)的行為。
// 如果既想取消默認(rèn)的行為,又想阻止事件起泡,這個(gè)事件處理函數(shù)必須返回false。
復(fù)制代碼 代碼如下:
  one : function(type, data, fn) {
   var one = jQuery.event.proxy(fn || data, function(event) {
       jQuery(this).unbind(event, one);
      return (fn || data).apply(this, arguments);/this->當(dāng)前的元素
       });
      return this.each(function() {
       jQuery.event.add(this, type, one, fn && data);
      });
   },

  One與bind基 本上差不多,不同的在調(diào)用jQuery.event.add時(shí),把注冊(cè)的事件處理的函數(shù)做了一個(gè)小小的調(diào)整。One調(diào)用了 jQuery.event.proxy進(jìn)行了代理傳入的事件處理函數(shù)。在事件觸發(fā)調(diào)用這個(gè)代理的函數(shù)時(shí),先把事件從cache中刪除,再執(zhí)行注冊(cè)的事件函 數(shù)。這里就是閉包的應(yīng)用,通過閉包得到fn注冊(cè)的事件函數(shù)的引用。

//一個(gè)模仿懸停事件(鼠標(biāo)移動(dòng)到一個(gè)對(duì)象上面及移出這個(gè)對(duì) 象)的方法。
//這是一個(gè)自定義的方法,它為頻繁使用的任務(wù)提供了一種“保持在其中”的狀態(tài)。
//當(dāng)鼠標(biāo)移動(dòng)到一個(gè)匹配的元素上面時(shí),會(huì) 觸發(fā)指定的第一個(gè)函數(shù)。當(dāng)鼠標(biāo)移出這個(gè)元素時(shí),
/會(huì)觸發(fā)指定的第二個(gè)函數(shù)。而且,會(huì)伴隨著對(duì)鼠標(biāo)是否仍然處在特定元素中的檢測(cè)(例如,處在div 中的圖像),
 //如果是,則會(huì)繼續(xù)保持“懸?!睜顟B(tài),而不觸發(fā)移出事件(修正了使用mouseout事件的一個(gè)常見錯(cuò)誤)。
    hover : function(fnOver, fnOut) {
      return this.bind('mouseenter', fnOver).bind('mouseleave', fnOut);
   },



  Hover則是建立在bind的基礎(chǔ)之上。

//每次點(diǎn)擊后依次調(diào)用函數(shù)。
toggle : function(fn) {  
var args = arguments, i = 1;
while (i < args.length)//每個(gè)函數(shù)分配GUID
    jQuery.event.proxy(fn, args[i++]);//修改后的還在args中
return this.click(jQuery.event.proxy(fn, function(event) {//分配GUID     this.lastToggle = (this.lastToggle || 0) % i;//上一個(gè)函數(shù)      event.preventDefault();//阻止缺省動(dòng)作
    //執(zhí)行參數(shù)中的第幾個(gè)函數(shù),apply可以采用array-like的參數(shù)
    return args[this.lastToggle++].apply(this,arguments)||false;
  }));
  },

   Toggle中參數(shù)可以是多個(gè)fn。先把它們代碼生成UUID。之后調(diào)用click的方法來注冊(cè)再次進(jìn)行代理的callback。這個(gè)函數(shù)在事件觸發(fā)時(shí) 運(yùn)行,它先計(jì)算上一次是執(zhí)行了參數(shù)中的那個(gè)函數(shù)。之后阻止缺省動(dòng)作。之后找到下一個(gè)函數(shù)運(yùn)行。

//為jquery對(duì)象增加常用 的事件方法
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) {
         return fn ? this.bind(name, fn) : this.trigger(name);
       };});

   Jquery增加了一個(gè)常用的事件處理方法,包含上面調(diào)用的click。這里可以看出這里還是調(diào)用bind進(jìn)行注冊(cè)。當(dāng)然這里還可以通過程序?qū)崿F(xiàn)去觸發(fā) 事件。



  上面的眾多方法都是注冊(cè)事件,其最終都落在jQuery.event.add();來完成注冊(cè)的功能。如果我們采用Dom0或DOM1 的事件方法,我們會(huì)采用elem.onclick=function(){}來為元素的某一種事件來注冊(cè)處理函數(shù)。這個(gè)最大的缺點(diǎn)就是每個(gè)一個(gè)事件只是一 個(gè)處理函數(shù)。在dom1的方式中有改進(jìn),我們可以采用elem.addEventListener(type, handle, false)為元素的事件注冊(cè)多個(gè)處理函數(shù)。

  這樣的處理方式還不是很完美,如果我們只這個(gè)事件運(yùn)行一次就有點(diǎn)麻煩了。我們要在事件的處 理函數(shù)中最后進(jìn)行elem.removeEventListener來取消事件的監(jiān)聽。這樣做可能會(huì)有事務(wù)上的問題。如果第一個(gè)事件處理函數(shù)在沒有取消事 件監(jiān)聽之前,就再次觸發(fā)了怎么辦?

  還有采用瀏覽器的方式,它不支持自定義事件的注冊(cè)和處理,還不能為多個(gè)事件注冊(cè)同一個(gè)處理函數(shù)。
復(fù)制代碼 代碼如下:
jQuery.event = {// add 事件到一個(gè)元素上。
add : function(elem, types, handler, data) {
if (elem.nodeType == 3 || elem.nodeType == 8) return;// 空白節(jié)點(diǎn)或注釋
  // IE不能傳入window,先復(fù)制一下。
if (jQuery.browser.msie && elem.setInterval) elem = window;
// 為handler分配一個(gè)全局唯一的Id
if (!handler.guid)  handler.guid = this.guid++;
// 把data附到handler.data中
if (data != undefined) {                       ①
var fn = handler;
handler =this.proxy(fn,function(){return fn.apply(this,arguments);});
handler.data = data;
  }
// 初始化元素的events。如果沒有取到events中值,就初始化data: {}    ②
var events =jQuery.data(elem,"events")||jQuery.data(elem,"events",{}),
// 如果沒有取到handle中值,就初始化data: function() {....}     ③
handle = jQuery.data(elem, "handle")|| jQuery.data(elem, "handle",
function() {//處理一個(gè)觸發(fā)器的第二個(gè)事件和當(dāng)page已經(jīng)unload之后調(diào)用一個(gè)事件。
    if (typeof jQuery != "undefined"&& !jQuery.event.triggered)
      return jQuery.event.handle.apply(//callee.elem=handle.elem
          arguments.callee.elem, arguments);
      });
// 增加elem做為handle屬性,防止IE由于沒有本地Event而內(nèi)存泄露。
handle.elem = elem;
// 處理采用空格分隔多個(gè)事件名,如jQuery(...).bind("mouseover mouseout", fn);
jQuery.each(types.split(/s+/), function(index, type) {    ④
  // 命名空間的事件,一般不會(huì)用到。
var parts = type.split(".");type = parts[0];handler.type = parts[1];
  // 捆綁到本元素type事件的所有處理函數(shù)
var handlers = events[type];                     ⑤
if (!handlers) {// 沒有找到處理函數(shù)列表就初始化事件隊(duì)列
    handlers = events[type] = {};
   // 如果type不是ready,或ready的setup執(zhí)行返回false         ⑥
if (!jQuery.event.special[type]|| jQuery.event.special[type].setup
    .call(elem, data) === false) {// 調(diào)用系統(tǒng)的事件函數(shù)來注冊(cè)事件
if(elem.addEventListener)elem.addEventListener(type,handle,false);
else if (elem.attachEvent)elem.attachEvent("on" + type, handle);
     }
}
// 把處理器的id和handler形式屬性對(duì)的形式保存在handlers列表中,
// 也存在events[type][handler.guid]中。
handlers[handler.guid] = handler;                  ⑦
// 全局緩存這個(gè)事件的使用標(biāo)識(shí)
jQuery.event.global[type] = true;
});
  
  elem = null; // 防止IE內(nèi)存泄露。
  },
  guid : 1,
  global : {},



  jQuery.event.add通過jQuery.data把事件相關(guān)的事件名和處理函數(shù)有機(jī)有序地組合起存放在 jQuery.cache中與該元素對(duì)應(yīng)的空間里。我們就一個(gè)例子分析一下add的過程中:假如我們招待下面 jQuery(e1).bind("mouseover mouseout", fn0);jQuery(e1).bind("mouseover mouseout", fn1)的語句。

  在jQuery(e1).bind("mouseover mouseout", fn0);時(shí),②③都不可能從cache取到數(shù),先初始化。此時(shí)的cache:{e1_uuid:{events:{},handle:fn}}。接著在 ⑤會(huì)為mouseover mouseout名初始化。此時(shí)的cache: {e1_uuid:{events:{ mouseover:{}, mouseout:{}},handle:fn}}。在⑥處向?yàn)g覽器的事件中注冊(cè)處理函數(shù)。接著⑦會(huì)把處理函數(shù)到事件名中。此時(shí)的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},handle:fn}}。這里可以看出為采用proxy為函數(shù)生成uuid的作用了。

   在jQuery(e1).bind("mouseover mouseout", fn1)時(shí),②③都從cache取到數(shù)據(jù){e1_uuid:{events:{mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}},接著在⑤取到mouseover:{fn0_uuid:fn0},mouseout:{ fn0_uuid:fn0}的引用。接著⑦會(huì)把處理函數(shù)注冊(cè)到事件名中。此時(shí)的cache: {e1_uuid:{events:{mouseover:{fn0_uuid:fn0, fn1_uuid:fn1,},mouseout:{ fn0_uuid:fn0, fn1_uuid:fn1}},handle:fn}}。

  jQuery.event.add很重要的任務(wù) 就是把注冊(cè)的事件函數(shù)有序地存放起來。以便remove和fire事件的函數(shù)能找到。

//{elem_uuid_1:{events:{mouseover:{fn_uuid:fn1,fn_uuid1:fn2},
       //mouseout:{fn_uuid:fn1,fn_uuid1:fn2}},handle:fn}}

   6.2.2 trigger



  注冊(cè)了事件,如onclick。那么當(dāng)用戶點(diǎn)擊這個(gè)元素時(shí),就會(huì)自動(dòng)觸發(fā)這個(gè)事件的已經(jīng)注冊(cè)的事件處理函數(shù)。但是我們有的時(shí)候要采用程 序來模擬事件的觸發(fā)就得采用強(qiáng)迫觸發(fā)某個(gè)事件。在IE中我們可以采用.fireEvent()來實(shí)現(xiàn)。如:<form onsubmit="a()" >中,如果button的form.submit()的方式提交表單,是不會(huì)主動(dòng)觸發(fā)onsumbit事件的,如果必須的話,就要在submit 前$(“:form”)[0].fireEvent("onsubmit”,),這樣就會(huì)觸發(fā)該事件。

  在mozilla中有三個(gè)步驟:   var  evt  =  document.createEvent('HTMLEvents');

   evt.initEvent('change',true,true);  t.dispatchEvent( evt );

  在 prototype是采用這樣的方式來實(shí)現(xiàn)的。那么jquery中呢,它的實(shí)現(xiàn)方式有一點(diǎn)不一樣。
復(fù)制代碼 代碼如下:
trigger : function(type, data, fn) {
return this.each(function() {
    jQuery.event.trigger(type, data, this, true, fn);
      }); },

   Trigger有三個(gè)參數(shù),data參數(shù)是為了注冊(cè)的事件函數(shù)提供了實(shí)傳。如果data[0]中preventDefault存在,data[0]就可 以做為用戶自定義的包裹事件的空間。Fn是可以為事件提供一個(gè)即時(shí)即用的事件處理方法。也就是在沒有注冊(cè)事件的情況下也可以通過傳入處理函數(shù)來處理事件。 如果已經(jīng)注冊(cè)了,那就是在原來的事件處理函數(shù)之后執(zhí)行。

  //這個(gè)方法將會(huì)觸發(fā)指定的事件類型上所有綁定的處理函數(shù)。但不會(huì) 執(zhí)行瀏覽器默認(rèn)動(dòng)作.
triggerHandler : function(type, data, fn) {
return this[0]&& jQuery.event.trigger(type,data,this[0],false,fn);
   },



  triggerHandle通過把jQuery.event.trigger的donative參數(shù)設(shè)為false,來阻止執(zhí)行瀏覽器 默處理方法。它與trigger不現(xiàn)的一點(diǎn),還在于它只是處理jquery對(duì)象的第一個(gè)元素。

  上面兩個(gè)方法都調(diào)用了 jQuery.event.trigger來完成任務(wù):
復(fù)制代碼 代碼如下:
trigger : function(type, data, elem, donative, extra) {
  data = jQuery.makeArray(data);//data可以為{xx:yy}
  //支持getData!這樣的形式,exclusive = true表現(xiàn)會(huì)對(duì)add的注冊(cè)的
  //事件的所有函數(shù)進(jìn)行命名空間的分種類的來執(zhí)行。
if (type.indexOf("!") >= 0) {             ①
    type = type.slice(0, -1);var exclusive = true;
    }
if (!elem) {// 處理全局的fire事件            ②
  if (this.global[type])
    jQuery.each(jQuery.cache, function() {
     // 從cache中找到所有注冊(cè)該事件的元素,觸發(fā)改事件的處理函數(shù)
      if (this.events && this.events[type])
       jQuery.event.trigger(type, data, this.handle.elem);
      });
  } else {// 處理單個(gè)元素事件的fire事件         ?、?
   if (elem.nodeType == 3 || elem.nodeType == 8)  return undefined;
   var val, ret, fn = jQuery.isFunction(elem[type] || null),
   // 如果data參數(shù)傳進(jìn)入的不是瀏覽器的event對(duì)象的話,event變量為true.
  //如果data參數(shù)本身是婁組,那么第一個(gè)元素不是 瀏覽器的event對(duì)象時(shí)為true.
  //對(duì)于event為true。即沒有event傳進(jìn)入,先構(gòu)建一個(gè)偽造的event對(duì)象存在 data[0]。
  event = !data[0] || !data[0].preventDefault;
  // 在沒有傳入event對(duì)象的情況下,構(gòu)建偽造event對(duì)象。
  if (event) {//存到數(shù)組中的第一個(gè)            ?、?
     data.unshift( { type : type,target : elem,
       preventDefault : function() {},stopPropagation :
function() {}, timeStamp : now()  });
    data[0][expando] = true; // 不需要修正偽造的event對(duì)象
    }
   data[0].type = type; //防止事件名出錯(cuò)
  //表現(xiàn)會(huì)進(jìn)行事件注冊(cè)函數(shù)的分類(命名空間)執(zhí)行。不是所有的。
    if (exclusive) data[0].exclusive = true;
  
  //與prototype等傳統(tǒng)的處理 方式不一樣,沒有采用fireEvent來
  //來fire通過注冊(cè)到瀏覽器事件中的事件處理方法。
  //這里分了三步,先fire 通過jQuery.event.add來注冊(cè)的事件,這個(gè)事件
  //有可能是自定義的事件(沒有注冊(cè)到瀏覽器事件中)。
  //第二步 是fire通過elem.onclick方式注冊(cè)的事件的本地處理函數(shù)
   //第三步是fire默認(rèn)的事件處理方式(在本地的onclick的方式注冊(cè)
   //不存在的情況下)?! ?
// 這里是觸發(fā)通過jQuery.event.add來注冊(cè)的事件,
   var handle = jQuery.data(elem, "handle");     ?、?
   if (handle)val = handle.apply(elem, data); //這里data分成多個(gè)參數(shù)
  //處理觸發(fā)通過elem.onfoo=function()這樣的注冊(cè)本地處理方法,
  //但是是 對(duì)于links 's .click()不觸發(fā),這個(gè)不會(huì)執(zhí)行通過addEvent
  //方式注冊(cè)的事件處理方式?!    ?
  if ((!fn || (jQuery.nodeName(elem, 'a') && type == "click")) ⑥
     && elem["on"+ type]&& elem["on"+type].apply(elem,data) === false)
   val = false;
//額外的函 數(shù)參數(shù)的開始幾個(gè)是通過data給定的。這里會(huì)把偽造加上的event給去掉。
//它的最后一個(gè)參數(shù)是一系列的事件處理函數(shù)返回的結(jié)果,一般為 bool值
//這個(gè)函數(shù)可以根據(jù)這個(gè)結(jié)果來處理一個(gè)掃尾的工作。
  if (event) data.shift();
// 處理觸發(fā)extra給定的函數(shù)處理。
  if (extra && jQuery.isFunction(extra)) {           ⑦
    ret = extra.apply(elem, val == null ? data : data.concat(val));
    //如果這個(gè)函數(shù)有返回值,那么trigger的返回值就是它的返回值
    //沒有的 話就是串連的事件處理函數(shù)的最后一個(gè)返回值。一般為bool
    if (ret !== undefined)  val = ret;
    }
  // 觸發(fā)默認(rèn)本地事件方法,它是在沒有如.onclick注冊(cè)事件
  //加上前面的執(zhí)行事件處理函數(shù)返回值都不為 false的情況下,才會(huì)執(zhí)行。
  //它還可以通donative來控制是否執(zhí)行。
  //如form中可以采用 this.submit()來提交form.
  if (fn && donative !== false && val !== false    ?、?
       && !(jQuery.nodeName(elem, 'a') && type == "click")) {
    this.triggered = true;
    try {elem[type]();  //對(duì)于一些hidden的元素,IE會(huì)報(bào)錯(cuò)
       } catch (e) {}
    }
  this.triggered = false;
  }
return val;
},



  Jquery的fire事件的方法與prototype中實(shí)現(xiàn)是完全不一樣的。Ext、YUI沒有提供強(qiáng)迫觸發(fā)事件的方法。對(duì)于一般的 思維,程序來觸發(fā)瀏覽器的事件就應(yīng)該采用fireEvent或dispatchEvent方法來運(yùn)行。

  但是jquery采用一種不同的 方法。對(duì)于通過jquery.event.add來注冊(cè)的事件(不管是自定義的還是注冊(cè)到瀏覽器事件),它保存在一個(gè)與元素及事件名相對(duì)應(yīng)的cache 中。在瀏覽器的觸發(fā)中,這個(gè)是沒有什么作用。但是它是為了通過等程序來強(qiáng)迫觸發(fā)時(shí),從cache中取到對(duì)應(yīng)的事件處理函數(shù)。這個(gè)時(shí)候就拋開了瀏覽器的事 件。在這里還可以執(zhí)行一些自定義的事件函數(shù)。如⑤處。

  對(duì)于通過html的標(biāo)簽中如click或 elem.onclick=function(){}形式注冊(cè)的事件函數(shù)。在⑥處它采用執(zhí)行元素的如onclick形式的回調(diào)函數(shù)就可以。通過這種 dom0的方式只能注冊(cè)一個(gè)函數(shù)。

  有的時(shí)候,如果沒有onclick這樣的事件處理函數(shù),瀏覽器會(huì)執(zhí)行默認(rèn)的處理函數(shù)。如 form.submit()。⑧處可以看出對(duì)于這樣的默認(rèn)的事件處理,還可以通過參數(shù)donative來控制。

  程序手動(dòng)強(qiáng)迫觸發(fā)事件, 有一點(diǎn)問題就是event是怎么生成,就是沒有瀏覽器生成event傳入到函數(shù)中。Prototype采用了是新生成的dataavailable的事 件。這樣的事件也沒有什么作用。Jquery也采用fake的方式偽造一個(gè)一個(gè)事件,如④,它比prototype的事件好處在于它能通過trigger 的函數(shù)的參數(shù)來傳入需要的event。Prototype則不能。

  通過上面的分析,隱隱可以看出Jquery是通過模擬瀏覽器的觸發(fā)事 件的執(zhí)行過程來構(gòu)建這個(gè)trigger的函數(shù)的。先執(zhí)行dom1方式(addEvent)注冊(cè)的事件,再執(zhí)行dom0方式注冊(cè)的事件,最后看看要不要執(zhí)行 默認(rèn)的事件處理。

  在⑦處,我們可以看出trigger還可能通過傳入回調(diào)函數(shù)和參數(shù)來完成對(duì)執(zhí)行的事件處理函數(shù)的結(jié)果進(jìn)行判斷處理,形 成新結(jié)果通過trigger的函數(shù)返回。這在有的時(shí)候是很有用的。



  除了這些,它還能對(duì)于事件的處理函數(shù)進(jìn)行分類(namespace),可以在合適的時(shí)候調(diào)用事件的不同分類的的處理函數(shù)(通過 jquery.event.add來注冊(cè))。這個(gè)分類的處理在handle實(shí)現(xiàn)。
復(fù)制代碼 代碼如下:
  handle : function(event) {
    // 返回 undefined or false
    var val, ret, namespace, all, handlers;
    //修改了傳入的參數(shù),這里是引用。
    event = arguments[0] = jQuery.event.fix(event || window.event);
    // 命名空間處理
     namespace = event.type.split(".");
    event.type = namespace[0];
     namespace = namespace[1];
    // all = true 表明任何 handler,namespace不存在,同時(shí)
    //event.exclusive不存在或?yàn)榧贂r(shí),all=true.
    all = !namespace && !event.exclusive;
    // 找到元素的events中緩存的事件名的處理函數(shù)列表
    handlers = (jQuery.data(this, "events") || {})[event.type];
    for (var j in handlers) {// 每個(gè)處理函數(shù)執(zhí)行
       var handler = handlers[j];
      // Filter the functions by class
       if (all || handler.type == namespace) {
       // 傳入引用,為了之后刪除它們
        event.handler = handler;
       event.data = handler.data;//add的時(shí)候加上的
       ret = handler.apply(this, arguments);// 執(zhí)行事件處理函數(shù)
        if (val !== false)
         val = ret;// 只要有一個(gè)處理函數(shù)返回false,本函數(shù)就返回false.
       if (ret === false) {// 不執(zhí)行瀏覽器默認(rèn)的動(dòng)作
         event.preventDefault();
          event.stopPropagation();
       }
      }
    }
    return val;  }

JavaScript技術(shù)jQuery源碼分析之Event事件分析,轉(zhuǎn)載需保留來源!

鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。

主站蜘蛛池模板: 综合久久久久久久综合网 | 色婷亚洲 | 欧美日韩国产精品 | 国产色在线观看 | 激情欧美一区二区三区 | 一区小说二区另类小说三区图 | 亚洲欧美成人网 | 国产xxx在线 | 国产在线播放91 | 午夜丁香婷婷 | 国产老妇xxxxxbb亚洲老妇 | 激情国产视频 | 91精品国| 色老板免费| 国内精品久久久久影院不卡 | 91精品综合国产在线观看 | 一区一区三区产品乱码 | 国产成人高清视频 | 黄网在线免费观看 | 日韩中文字幕在线有码视频网 | 在线观看永久免费 | 欧美专区一区二区三区 | 福利精品视频 | 色多多www | 激情都市亚洲 | 成人福利免费视频 | 国产精品视频1区 | 婷婷五月五 | 日本精品国产 | 色网在线免费观看 | 婷婷久久五月天 | 日本综合欧美一区二区三区 | 精品欧美一区二区三区在线观看 | 精品国产午夜肉伦伦影院 | 国产免费播放一区二区 | 一级鲁丝片 | 好吊妞视频这里只有精品 | 一级特黄色毛片免费看 | 美女很黄很黄是免费的·无遮挡网站 | 国产在线激情 | 欧美黑人巨大xxxxxxxx |