DOM事件模型學習

文中涉及大量內容來自于PPK的博客

現代前端開發應該要遵守:

html展示文檔內容,css渲染頁面效果,javascript提供交互

瀏覽器能夠提供交互可以追溯到Netscape公司在其第二個版本中支持javascript語言,隨后與微軟之間的瀏覽器大戰,以及w3c標準制定的落后,導致至今被詬病的瀏覽器兼容問題,這些問題中關于DOM事件模型無疑是棘手的一個。

在 Introduction to Events中PPK提到了如何學習javascript中的事件模型,概括來說就是理解:

  1. four event registration models
  2. two event accessing models
  3. two event orders

four event registration models

  • **inline event registration model **

下面的代碼應該見過,直接在html文檔中對相應的元素注冊事件處理函數,好處是直觀,壞處也是直觀,破壞了文章開始提到的內容-展現-交互分離的原則

<A HREF="somewhere.html" onClick="doSomething(this);return false;">

行內注冊模型中this對象可以直接以參數的形式傳人,避免了查找觸發元素的問題。

  • Traditional event registration model

下面這種事件注冊模型是在Netscape3中引入的,算是事實上的標準,當時瀏覽器大戰還未開始, IE基于Netscape用戶基數巨大,被迫實現了該標準。

element.onclick = doSomething;

該種事件注冊模型this值就是觸發事件的元素本身,該種事件模型的缺點就是一個事件只能注冊一個處理函數,如果多次注冊會發生之后注冊的事件處理函數覆蓋之前的函數。

element.onclick = startDragDrop;
element.onclick = spyOnUser;

spyOnUser會覆蓋之前的startDragDrop。

  • Advanced event registration models

為了改進Netscape事件注冊模型的缺陷,w3c開發了自己的事件注冊模型,對于傳統方式不能處理的給一個事件注冊多個事件處理函數的問題,新的模型可以輕松做到

element.addEventListener('click',startDragDrop,false)
element.addEventListener('click',spyOnUser,false)

要移除某一個事件處理函數也很容易

element.removeEventListener('click',spyOnUser,false)

該種事件注冊模型this值也是觸發事件的元素本身
存在的一個問題是,如何知道某一元素是否注冊了相應的事件,對于傳統的時間注冊模型,可以:

alert(element.onclick)

值得欣喜的是:DOM Level 3 Events W3C 添加了eventListenerList 接口存儲當前注冊事件的元素的所有事件句柄列表,另外即便不清楚元素是否注冊了相應的事件,我們也可以使用removeEventListener()直接移除,因為該接口在移除一個并沒有注冊的事件是并不會報錯。

  • Microsoftevent registration models

最后要說的是IE自己新搞的一套事件注冊模型,跟w3c的接口有異曲同工之效,例如可以使用下面的方式注冊

element.attachEvent('onclick',startDragDrop)
element.attachEvent('onclick',spyOnUser)

唯一不足的問題是:IE的模型只支持事件冒泡階段,并不支持事件捕獲。
其次IE的事件模型中的事件處理函數只是函數引用,什么意思呢,我們了解到javascript中this的值是隨著上下文變化而變化的,這樣就導致事件處理函數在被調用時this的值指向了window對象。而window對象在這里是沒一點用的。

two event accessing models

ok,已經為元素綁定了事件處理函數,接下來的問題就是如果獲知關于事件本身更多的信息,例如對于鼠標單擊事件,想要知道鼠標的位置, 非常抱歉的是,在那個瀏覽器大戰的年代,Netscape和微軟處于自身戰略的考慮,各自引入了自己的事件訪問模型,要命的是這兩種模型完全不兼容。
為了說明這兩種事件訪問模型,PPK給出了5個問題以及相應的回答:

  1. 事件的類型是什么?

    ( e | window.event).type
    
  2. 事件target對應的HTML元素是誰?

    e = e | window.event
    target = e.target || e.srcElement;
    if(target.nodeType == 3){
        target =  target.parentNode;
    }
    
  3. 事件觸發過程中,哪一個鍵被按下?

     e = e | window.event;
     if (e.keyCode){
         code = e.keyCode;
     } else if (e.which){
         code = e.which;
     }
     var character = String.fromCharCode(code);
    
  4. 事件觸發過程中,用戶使用的時鼠標的哪一個鍵?

首先是有兩個屬性可以判斷鼠標的哪一個鍵點擊:which和button,同時要注意這兩個屬性不總是在click事件中正常工作,安全的做法是使mousedown或者 mouseup事件 ,which是舊式Netscape瀏覽器中的屬性,

    左鍵用1表示 
    中鍵(鼠標滾輪)是2 
    右鍵用3表示 

button把事情全搞砸了,W3C給出的值是:

  • Left button – 0
  • Middle button – 1
  • Right button – 2

而微軟的實現確是:

  • Left button – 1
  • Middle button – 4
  • Right button – 2

關于鼠標按鍵的兼容上遇到了困難,你沒法區分用戶單擊了鼠標左鍵還是中鍵,搞笑的是微軟和w3c在關于鼠標右鍵的問題上達成一致,下面是關于鼠標右鍵的兼容方案:

function doSomething(e) {
    var rightclick;
    if (!e)  var e = window.event;
    if (e.which) 
            rightclick = (e.which == 3);
    else if (e.button) 
            rightclick = (e.button == 2);
    alert('Rightclick: ' + rightclick); // true or false
}  

5.事件觸發過程中鼠標的位置坐標是什么?

對于鼠標坐標計算的兼容問題同樣嚴峻,盡管規范提供了不少于6個鼠標坐標屬性,但是沒有一個可信賴的跨瀏覽器方式去找到鼠標相對于文檔document的坐標,下面是作者提供的一個方案

    function doSomething(e) {
            var posx = 0;
            var posy = 0;
            if (!e) var e = window.event;
            if (e.pageX || e.pageY){
                    posx = e.pageX;
                    posy = e.pageY;
            }else if (e.clientX || e.clientY){
                    posx = e.clientX + document.body.scrollLeft+ document.documentElement.scrollLeft;
                    posy = e.clientY + document.body.scrollTop+ document.documentElement.scrollTop;
            }
    }

two event orders

w3c在event orders的問題上扮演了和事佬的角色,博采眾家之長,產生了w3c的事件模型,在w3c的事件模型中,首先進行事件捕獲的階段,直到到達target元素,然后進行事件冒泡的過程:

事件有捕獲或者冒泡階段,實際的應用價值是什么呢?個人觀點僅供參考:

  1. 對于復雜的界面,逐一給每一個元素單獨綁定事件顯得繁瑣枯燥,一種可操作的方案就是讓事件冒泡到根元素,然后由根元素做統一處理。
  2. 對于復雜界面,為每個元素綁定事件勢必消耗大量資源,統一由根元素處理節省了資源。
  3. 采用事件冒泡的方式處理事件,使得對于未來插入文檔中的元素也能觸發之前綁定的事件,這一點可以參考jquery中delegete方法的實現原理,具體可以參考這篇文字

既然事件有冒泡的特性,那有沒有一種方式可以取消這種特性呢?
在IE中可以這樣

window.event.cancelBubble = true

遵循w3c規范的瀏覽器中可以這樣

e.stopPropagation()

currentTarget 對象

前面講過 target 指向的是當前事件正在發生在哪個元素身上,要明確一點是:不論是在事件捕獲還是冒泡階段,target對象是不會發生變化的,那么如果多個元素綁定了同一事件,如何知道哪個元素正在處理事件呢? w3c引入了currentTarget 對象,可惜IE沒有相似對應的屬性.

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容

  • 總結: 鼠標事件 1.click與dbclick事件$ele.click()$ele.click(handler(...
    阿r阿r閱讀 1,628評論 2 10
  • Spring Cloud為開發人員提供了快速構建分布式系統中一些常見模式的工具(例如配置管理,服務發現,斷路器,智...
    卡卡羅2017閱讀 134,832評論 18 139
  • 聲明:本文來源于http://www.webzsky.com/?p=731我只是在這里作為自己的學習筆記整理一下(...
    angryyan閱讀 7,079評論 1 6
  • 有關jQuery 事件模塊結構部分的分析可以參考這篇文章,作者分析的很不錯,贊一個。 進題之前,有幾個名詞 Eve...
    江楓閱讀 1,464評論 1 13
  • 媽媽的病床邊,爸爸回憶起結婚之前媽媽農藥中毒的事情,那時候還沒結婚,媽媽給麥苗噴灑農藥的時候不小心中了毒,暈暈乎乎...
    Bactery閱讀 360評論 0 0