從程式設計小白到全棧開發:瞭解事件機制

at_1發表於2021-09-09

在上一篇文章中,我們初步瞭解了在HTML中處理使用者操作的知識,最主要的,就是如何對指定的DOM元素新增事件監聽以獲取使用者操作,並進行後續的處理。這裡所使用到的這種基於事件的處理方式,其本質是一種訊息傳遞機制,我們稱之為事件機制。

簡介

在事件機制中,有3樣最重要的東西:

  • 事件生產者

  • 事件物件

  • 事件消費者

事件生產者可以產生一系列的事件物件,然後事件物件攜帶著必要的資訊,傳遞給事件消費者。

圖片描述

可以看出來,這是一種單向的訊息傳遞模型,事件訊息總是從生產者傳遞到消費者。那既然事件機制傳遞訊息是單向的,那麼如果兩個物件間要透過事件機制實現雙向通訊,是否可能呢?這太簡單了,把它們既作為生產者又作為消費者就行了:

圖片描述

這個理解起來應該不難吧?

接著呢,一個事件生產者所產生的事件,其實可以有多個消費者:

圖片描述

反之,一個事件消費者,也可以消費由多個生產者產生的事件:

圖片描述

好吧,我知道上面所描述的這些什麼生產者啊消費者的概念,對於一個初學者來說,聽起來還是有點迷糊,不太容易理解這套機制到底是怎樣工作的。那我們來整一個通俗易懂的例子吧:

我家小區門口有閘機,需要刷卡才能進入。如果有陌生來訪者,保安大哥就出現了,詢問來訪者去幾棟、幾零幾室、戶主是誰等資訊,答對了才登記並放行。

這個例子中,有著和我們上面講的概念一一對應的3個重要物件:

  • 事件生產者:陌生來訪者

  • 事件:無卡訪問

  • 事件消費者:保安大哥

保安大哥的職責,就是時刻監視著是否有陌生來訪者產生了“無卡訪問”事件,一旦產生,保安大哥就會立刻啟動他應對這一事件的處理流程:詢問並核對資訊,答對後登記並放行。

這樣一講,是不是好理解多了?

事件冒泡

在講事件冒泡這個有點抽象的概念之前,我還是想以保安大哥來舉個例子。

雖然有陌生無卡訪問者的來訪,但是有些陌生無卡來訪者的情況比較特殊,而保安大哥的許可權還是比較小的,自己處理不了,這個時候,就需要通知他的上級----保安隊長來處理,如果保安隊長能處理,則他處理掉就完事兒了(或處理後同時上報給他的上級);如果他也仍然處理不了,就需要再通知他的上級----小區物業主管來處理......

這種將事件層層向上級通報的機制,就被形象的稱作事件冒泡。

好,那麼這個概念對應到我們的HTML DOM程式設計中來,具體會是個什麼樣子呢?我們先前已經明白了一個HTML檔案對應一棵DOM樹,DOM節點之間也有父子層級關係,所以當在一個子節點上觸發一個事件,該事件也會隨著DOM樹的層級路徑,由子節點向父節點進行層層傳遞,請看以下示例:

    
             
    function buttonClickHandler(event) {        console.log('button clicked')     }    function innerClickHandler(event) {        console.log('inner clicked')     }    function outerClickHandler(event) {        console.log('outer clicked')     }

以上程式碼中,我們建立了一個按鈕,這個按鈕擁有一個class為inner的

父節點,還有一個class為outer的
祖父節點。這三個DOM元素上,都分別設定了onclick事件監聽函式。我們來嘗試點選以下按鈕,看看會有什麼情況發生:

button clicked
inner clicked
outer clicked

我們的開發者工具控制檯上,列印出了這樣的三行結果。這個是我們預料之中的事情,因為事件冒泡在這裡起了作用:

  • 當我們用滑鼠在按鈕上點選的時候,一個click事件產生了,這個事件首先被接收到並被事先設定好的click事件處理函式buttonClickHandler進行處理;

  • 接著,這個事件透過冒泡,上升傳遞到父節點inner上,inner節點接受到這個事件後,同樣啟動了它的click事件處理函式innerClickHandler進行處理;

  • 最後,事件繼續上升,到達outer節點並被其click處理函式outerClickHandler進行處理。

那麼這個click事件到這裡就結束了,不再冒泡了麼?不,它會繼續冒泡,在它之上,至少還有節點呢,一棵DOM樹的根節點是,事件冒泡到這裡才會結束。

講到這裡,一定有反應快的朋友會問,有什麼辦法可以提前讓冒泡結束?因為冒泡有時候也會帶來副作用啊,會觸發父節點上本來不希望觸發的監聽函式。這個當然是有辦法來解決的!我們只要在不希望事件繼續冒泡的時候,呼叫event物件的stopPropagation函式,即可使事件終止冒泡了。我們把上面的示例程式碼稍微改一下:

function buttonClickHandler(event) {    console.log('button clicked')
    event.stopPropagation()
}

改動後,嘗試點選按鈕,你會發現,列印結果中,只會出現一行結果了,inner和outer不再會接受到透過冒泡上來的click事件,所以它們的click事件處理函式不再會因為點選按鈕而被觸發了:

button clicked

總結

事件機制是一種簡單有效的訊息傳遞機制,它不僅在前端的HTML DOM程式設計中被廣泛使用,在服務端的JavaScript開發中也擁有極高的使用價值。合理的使用好事件機制,可以讓你的程式碼架構變得更優雅。



作者:一斤程式碼
連結:
來源:簡書
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/1817/viewspace-2809542/,如需轉載,請註明出處,否則將追究法律責任。

相關文章