深刻理解js Dom事件機制(二)——添加事件處理程序

  1. 深刻理解js Dom事件機制(一)——事件流
事件就是當用戶或者瀏覽器自身執行的某種動做,諸如 click、mouseover等都是事件的名稱,那響應個事件的函數就稱爲事件處理程序(事件處理函數、事件句柄)。 事件處理程序的名字都是以on+事件名稱命名,好比 click事件的事件處理程序就是onclick, 爲某個事件指定事件處理程序的方式大體分爲三種。

一、HTML事件處理程序

這個很簡單,你們基本初學js的時候都應該用過,就再也不贅述,直接看實例代碼
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Html事件處理程序</title>
</head>
<body>
    <!-- 第一種:直接在html中定義事件處理程序和事件動做 -->
    <input type="button" value="clcik me" onclick="console.log(event.type, this.value);"> <!-- click click me -->
    <!-- 第二種:html中定義事件處理程序,執行的動做則調用其餘地方的腳本 -->
    <input type="button" value="happy" onclick="happy()">
</body>
<script type="text/javascript">
    function happy() {
        console.log(this === window);
        // true
    }
</script>
</html>
以上代碼展現了兩種html指定事件處理程序的方法,須要注意的是 第一種作法的this指向的是元素自己, 因此咱們能夠很容易的訪問元素自己的屬性,而第二種作法的this指向的window對象。
缺點:
  1. 存在時差問題,當用戶在元素出如今頁面就觸發事件,但有可能這個時候事件處理程序不具有執行的條件。
  2. html與js代碼耦合度高,這正是不少開發者放棄html事件處理程序的緣由。

二、DOM0級事件處理程序

這種方式首先須要取得一個dom元素對象的應用,而後將一個函數賦值給一個事件處理程序,這種方式在第四代瀏覽器中就已經出現,至今仍然爲如今瀏覽器所支持,緣由一是簡單,二是具備跨瀏覽器的優點。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>DOMO級事件處理程序</title>
</head>
<body>

    <input type="button" value="happy" id="happy">
</body>
<script type="text/javascript">
    var btn = document.getElementById('happy');
    btn.onclick = function () {
        console.log(this.value); // happy
    }
</script>
</html>
經過上面的代碼能夠看出,這種方法指定的事件處理程序中this是指向元素自己。相對應的這種方法也能夠刪除指定的事件處理程序: btn.onclick = null.

三、DOM2級事件處理程序

DOM2級事件定義了兩個方法,用於處理指定和刪除事件處理程序的操做:addEventListener()、removeEventListener(),它們都接受三個參數:要處理的事件名、事件處理函數、布爾值(true:在捕獲階段調用事件處理函數,false:在冒泡階段調用事件處理函數)。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>DOM2級事件處理程序</title>
</head>
<body>

    <input type="button" value="happy" id="happy">
</body>
<script type="text/javascript">
    var btn = document.getElementById('happy');
    btn.addEventListener('click',function happy() {
        console.log('事件捕獲階段被單擊')
    },true)
    btn.addEventListener('click',function happy() {
        console.log('事件冒泡階段被單擊')
    },false)
    btn.addEventListener('mouseover',function happy() {
        console.log('鼠標移入啦')
    })
</script>
</html>
從上述代碼中能夠看出:
  1. addEventListener能夠對一個元素添加多個事件處理程序,並能夠聲明是將事件處理程序添加到哪個階段(爲了保證兼容性、建議都將事件處理程序添加到冒泡階段)。
  2. 須要特別注意的是:removeEventListener移除事件處理函數的時候,傳入的事件事件處理函數必須和addEventListener傳入的相同,方可移除,這就意味着若是addEventListener中使用了一個匿名函數來做爲事件處理函數,那麼removeEventListener將沒法移除。

四、IE事件處理程序(IE8 && IE8 - && Opera)

IE實現了相似DOM中的兩個方法:attacheEvent()、detachEvent(),它們接受兩個參數:事件處理程序名稱、事件處理函數。因爲IE8以及更早的瀏覽器只支持冒泡事件流,因此經過attacheEvent()添加的事件處理程序都將在會被添加到冒泡階段。
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>IE事件處理程序</title>
</head>
<body>

    <input type="button" value="happy" id="happy">
</body>
<script type="text/javascript">
    var btn = document.getElementById('happy');
    btn.attachEvent('click',function happy() {
        console.log('事件冒泡階段被單擊')
    })
    btn.attachEvent('mouseover',function happy() {
        console.log('鼠標移入啦')
    })
</script>
</html>

與DOM2級方法的異同javascript

  • 相同:html

    一、均可以添加和移除事件處理程序,匿名函數均不可移除。
       二、均可以添加多個事件處理程序。
  • 不一樣:java

    一、IE的事件處理函數會在全局做用於執行,因此this指向window,而DOM方法中this指向元素對象引用
       二、當添加多個事件處理程序時:執行的順序和DOM2級事件處理程序相反。

五、跨瀏覽器事件處理程序

爲了保證事件處理的代碼能在大部分的瀏覽器下獲得一致性的運行,咱們能夠恰當的使用瀏覽器能力檢測能力封裝一個通用的事件處理程序添加函數。
let eventUtil = {
    addEventHandle(element, eventType, handle) {
        if (Object.prototype.toString.apply(handle) !== '[object Function]') {
            throw new TypeError('handle invaild')
        }
        if (!element.addEventListener) {
            element.addEventListener(eventType,handle)
        } else if (element.attachEvent) {
            element.attachEvent(`on${eventType}`,handle)
        } else{
            element[`on${eventType}`] = handle
        }

    },
    removeEventHandle(element, eventType, handle) {
        if (Object.prototype.toString.apply(handle) !== '[object Function]') {
            throw new TypeError('handle invaild')
        }
        if (!element.removeEventListener) {
            element.removeEventListener(eventType,handle)
        } else if (element.detachEvent) {
            element.detachEvent(`on${eventType}`,handle)
        } else{
            element[`on${eventType}`] = null
        }

    }
}
上面的代碼很簡單,首先判斷瀏覽器是否支持addEventHandle, 若是支持就用它來添加事件程序,不然再判斷attachEvent,若是還不支持只能用Dom0級事件添加, 可是針對IE8--使用attachEvent添加事件處理程序時,this的指向並無作處理,包括事件觸發的階段等。
相關文章
相關標籤/搜索