天天看點

解密jQuery事件核心 - 自定義設計(三)對象之間通過直接方法調用來互動了解自定義事件的概念案例jQuery.trigger 與 document.dispatchEvent 區分trigger的幾種常見用法jQuery自定義事件原理trigger需要處理的問題源碼解讀總結

 本文重點:自定義事件

“通過事件機制,可以将類設計為獨立的子產品,通過事件對外通信,提高了程式的開發效率。”

<a></a>

1)對象A直接調用對象B的某個方法,實作互動;直接方法調用本質上也是屬于一種特殊的發送與接受消息,它把發送消息和接收消息合并為一個動作完成;

方法調用方和被調用方被緊密耦合在一起;因為發送消息和接收消息是在一個動作内完成,是以無法做到消息的異步發送和接收;

2)對象A生成消息-&gt;将消息通知給一個事件消息處理器(Observable)-&gt;消息處理器通過同步或異步的方式将消息傳遞給接收者;

這種方式是通過将消息發送和消息接收拆分為兩個過程,通過一個中間者來控制消息是同步還是異步發送;

在消息通信的靈活性方面比較有優勢,但是也帶來了一定的複雜度。但是複雜度一般可以由架構封裝,消息的發送方和接收方仍然可以做到比較簡單;

總的來說就是一種松耦合的處理,2個對象之間有太多緊密的直接關聯,應該要考慮通過消息通信解耦,進而提高應用程式的可維護性和重用性

在JS中,消息的通知是通過事件表達的,當代碼庫增長到一定的規模,就需要考慮将行為和自定義事件進行解耦。

類似DOM的行為:你在DOM節點(包括document對象)監聽并觸發自定義事件。這些事件既可以冒泡,也可以被攔截。這正是Prototype、jQuery和MooTools所做的。如果事件不能擴散,就必須在觸發事件的對象上進行監聽。

命名空間:一些架構需要你為你的事件指定命名空間,通常使用一個點号字首來把你的事件和原生事件區分開。

自定義額外資料:JavaScript架構允許你在觸發自定義事件時,向事件處理器傳送額外的資料。jQuery可以向事件處理器傳遞任意數量的額外參數。

通用事件API:隻用Dojo保留了操作原生DOM事件的正常API。而操作自定義事件需要特殊的釋出/訂閱API。這也意味着Dojo中的自定義事件不具有DOM事件的一些行為(比如冒泡)。 

聲明:我們往往需要在預定義的事件中加入一些特殊的變化(例如,需要Alt鍵按下才能觸發的單擊事件),MooTools運作你定義此類自定義事件。此類事件需要預先聲明,即便你隻是聲明他們的名字。任何未聲明的自定義事件不會被觸發。

理論太抽象,看看jQuery架構中如何使用事件

jQuery的事件自定義事件還是通過on綁定的,然後再通過trigger來觸發這個事件

這段代碼這樣寫似乎感覺不出它的好處,看了下面的例子也許你會明白使用自定義事件的好處了:

我們已一個頁籤的插件為例:

我們讓ul清單來響應點選事件,當使用者點選一個清單項時,給這個清單項添加一個名為active的類,同時将其他清單項中的active類移除,

以此同時讓剛剛點選的清單對應的内容區域也添加active類。

HTML:

jQuery

從上面的例子我們可以看到使用自定義事件回調使得頁籤狀态切換回調彼此分離,讓代碼變得整潔易讀。

浏覽器提供自定義事件接口,那麼就jQuery是不是利用這個原理呢?

第一種情況:DOM-events使用jQuery觸發。 觸發不會處理通過addEventListener綁定的事件 

另一種:DOM-events觸發使用本機createEvent / dispatchEvent方法與用jQuery.bind注冊事件偵聽器

這是一個問題,如果你與非jQuery代碼混合jQuery代碼。例如,jQuery移動模拟orientationchange事件基于視窗尺寸和大小事件但它使用jQuery觸發orientationchange事件。 觸發,是以不調用本機事件偵聽器。

在jQuery中,可以使用trigger()方法完成模拟操作。例如可以使用下面的代碼來觸發id為btn按鈕的click事件。

這樣,當頁面加載完畢後,就會立刻輸出想要的效果。

也可以直接用簡化寫法click(),來達到同樣的效果:

trigger()方法不僅能觸發浏覽器支援的具有相同名稱的事件,也可以觸發自定義名稱的事件。

例如為元素綁定一個“myClick”的事件,jQuery代碼如下:

想要觸發這個事件,可以使用下面的代碼來實作:

trigger(tpye[,datea])方法有兩個參數,第一個參數是要觸發的事件類型,第二個單數是要傳遞給事件處理函數的附加資料,以數組形式傳遞。通常可以通過傳遞一個參數給回調函數來差別這次事件是代碼觸發的還是使用者觸發的。

下面的是一個傳遞資料的例子:

triger()方法觸發事件後,會執行浏覽器預設操作。例如:

以上代碼不僅會觸發為input元素綁定的focus事件,也會使input元素本身得到焦點(浏覽器預設操作)。

如果隻想觸發綁定的focus事件,而不想執行浏覽器預設操作,可以使用jQuery中另一個類似的方法-triggerHandler()方法。

該方法會觸發input元素上綁定的特定事件,同時取消浏覽器對此事件的預設操作,即文本框指觸發綁定的focus事件,不會得到焦點。

看看demo

按照tigger綁定的方式

第一種是自定義的事件名aaa,第二種是浏覽器事件click

根據trigger的API,會處理冒泡這個關鍵點,

這個很明了,因為不是通過浏覽器系統觸發的,而是自動觸發的,是以這個事件對象要如何處理?

例如:事件名稱+命名空間

是以trigger觸發的時

那麼浏覽器click類型,自然是本身支援冒泡這樣的行為,通過stopPropagation阻止即可

當然一些事件,如focusin和 blur本身不冒泡,但 jQuery 為了跨浏覽器一緻性, jQuery 需要在這些事件上模拟了冒泡行為,jQuery要如何處理?

那麼如果是自定義的aaa的事件名,又如何處理冒泡?

附上源碼

解密jQuery事件核心 - 自定義設計(三)對象之間通過直接方法調用來互動了解自定義事件的概念案例jQuery.trigger 與 document.dispatchEvent 區分trigger的幾種常見用法jQuery自定義事件原理trigger需要處理的問題源碼解讀總結

初看trigger源碼部分,真有點暈,處理的hack太多了,但是仔細規劃下,無非就是解決上面提到的幾點問題

按照規範p4.trigger('click.aaa.ccc'),'click.aaa.ccc' 就是事件+命名空間的組合

判斷也挺巧妙,indexOf判斷有.是索引,即存在命名空間,然後踢掉第一個事件名

在on機制裡面就分析了,其實就是jQuery.Event類了

是以data就是事件回調傳回的[event,data],如果傳遞了資料就合并到data中

這個在很多地方用到,這個是用來做模拟事件的,比如提到的模拟聚焦冒泡之類的,下章再講

trigger與triggerHandler的本質差別實作在這裡了

其實大緻的手法都差不多了,無非就是周遊所有的元素節點了,排個隊列出來

解密jQuery事件核心 - 自定義設計(三)對象之間通過直接方法調用來互動了解自定義事件的概念案例jQuery.trigger 與 document.dispatchEvent 區分trigger的幾種常見用法jQuery自定義事件原理trigger需要處理的問題源碼解讀總結

<code>如果循環中最後一個cur是document,那麼事件是需要最後觸發到window對象上的,</code><code>将window對象推入元素隊列</code>

<code>為什麼最後要加window?</code>

<code> </code>

<code>接下來的處理邏輯,無非就是周遊每個節點,取出對應節點上的事件句柄,并確定事件不需要阻止冒泡</code>

當然每個元素上可能有多個事件,是以先确定事件綁定類型是delegateType還是bindType

<code>檢測緩存中該元素對應事件中包含事件處理器,</code><code>有則取出主處理器(jQuery handle)來控制所有分事件處理器</code>

<code>是以最終代碼又走到了</code>

<code>handle.apply(cur, data);</code>

<code>其實就是交給了事件派發管理了</code>

<code>jQuery.event.dispatch.apply( eventHandle.elem, arguments ) :</code>

<code>這時候事件就是按照dispatch的觸發規則,自行處理了,如果是浏覽器事件就會按照dispatch處理冒泡了,自定義的就過濾了</code>

<code></code>是以jQuery的結構 是一層套一層,必須要從頭看起來知道流程

還有一部分代碼,需要在特定的環境下才會觸發的,遇到的時候在說

是以整個trigger的核心,還是圍繞着資料緩存在處理的,通過on機制在jQuery.event.add的時候預處理好了

最終通過<code>jQuery.event.dispatch派發</code>

<code></code>通過trigger很好的模拟了浏覽器事件流程,但是美中不足的是對象的事件混淆其中 這就造成了 觸發對象事件的時候 最後會調用對象的相應方法

本文轉自艾倫 Aaron部落格園部落格,原文連結:http://www.cnblogs.com/aaronjs/p/3452279.html,如需轉載請自行聯系原作者

繼續閱讀