javascript----事件概述

事件處理程序

DOM0級事件處理程序

經過Javascript指定事件處理程序的傳統方式,就是將一個函數賦值給一個事件處理程序屬性。
每一個元素都有本身的事件處理程序屬性,這些屬性一般所有小寫,例如onclick。將這種屬性的值設置爲一個函數,就能夠指定事件處理程序。javascript

var btn = document.getElementById('myBtn');
// 添加事件處理程序
btn.onclick = function () {
    alert( this );//爲DOM元素btn
};
// 移除事件處理程序
btn.onclick = null;

優勢:1.簡單2.具備跨瀏覽器的優點
缺點:在代碼運行以前不會指定事件處理程序,所以這些代碼在頁面中位於按鈕後面,就有可能在一段時間怎麼點擊都沒反應,用戶體驗變差。html

DOM2級事件處理程序

定義了兩個方法,用於處理指定和刪除事件處理程序的操做:addEventListener()和removeEventListener()。三個參數,1.要處理的事件名。2.做爲事件處理程序的函數3.一個布爾值。最後這個布爾值爲true,表示在捕獲階段調用事件處理程序,false表示在冒泡階段調用事件處理程序。html5

// 添加多個事件處理程序
var btn = document.getElementById('myBtn');
btn.addEventListener('click',function (){
    alert( this );// 爲DOM元素btn
},false );
btn.addEventListener('click',function () {
    alert('Hello World');
},false);

// 移除事件處理程序
btn.removeEventListener('click',function () {
    // 匿名函數沒法被移除,移除失敗
},false);
   // 改寫
   var handler = function () {
    alert(this.id);
   };
   btn.addEventListener('click',handler,false);
   // 再次移除事件處理程序
   btn.removeEventListener('click',handler,false);// 移除成功

這兩個事件處理程序會按照添加他們的順序觸發。大多數狀況,都是將事件處理程序添加到事件流的冒泡階段,這樣能夠最大限度的兼容各類版本的瀏覽器。java

優勢: 一個元素能夠添加多個事件處理程序
缺點: IE8及如下瀏覽器不支持DOM2級事件處理程序。(包括IE8)chrome

IE事件處理程序

定義了兩個方法,與上相似:attachEvent(),detachEvent()。這兩個方法接收相同的兩個參數:事件處理程序名稱和事件處理程序函數。因爲IE8以及更早版本的瀏覽器只支持事件冒泡,因此經過detachEvent()添加的事件處理程序會被添加到冒泡階段。瀏覽器

var btn = document.getElementById('myBtn');
btn.attachEvent('onclick', function(){
    alert( this );// window
});
btn.attachEvent('onclick', funciton(){
    alert("HELLO, WORLD");
});

點擊按鈕,這兩個事件處理程序的觸發順序與上述恰好相反。不是按照添加事件處理程序的順序觸發,恰好相反。app

優勢:一個元素能夠添加多個事件處理程序
缺點:只支持IE。函數

跨瀏覽器的事件處理程序

var EventUtil = {
    addHandler : function ( ele, type, handler ) {
        if ( ele.addEventListener ) {
            ele.addEventListener( type, handler, false );
        } else if ( ele.attachEvent ) {
            ele.attachEvent( 'on' + type, handler );
        } else {
            ele['on' + type] = handler
        }
    },
    removeHandler: function ( ele, type, handler ) {
        if ( ele.removeEventListener ) {
            ele.removeEventListener( type, handler, false );
        } else if ( ele.detachEvent ) {
            ele.detachEvent( 'on' + type, handler );
        } else {
            ele[ 'on' + type ] = null;
        }
    }
}

事件對象

DOM中的事件對象

兼容DOM的瀏覽器會將一個event對象傳入到事件處理程序中。不管指定事件處理程序時使用什麼方法(DOM0級或DOM2)級,都會傳入event對象。event對象包含與建立它的特定事件有關的屬性和方法。觸發的事件類型不同,可用的屬性和方法也不同。不過,全部事件都有下表列出的成員性能

| 屬性/方法 | 類型 | 說明
| ---------—--- | ------------- | ------------
| bubbles
| cancebles
| currentTarget
| defaultPrevented
| detail
| evnetPhase
| preventDefault
| stopImmediatePropagation()
| stopPropagation()
| target
| trusted
| type
| viewthis

1.currentTarget與target

target :事件的目標對象
currenTarget : 其當前事件處理程序正在處理事件的那個元素

var btn = document.getElementById('myBtn');

btn.onclick = function ( e ) {
    console.log( this === e.currentTarget );// true
    console.log( this === e.target );// true
};

document.body.onclick = function ( e ) {
    console.log( this === e.currentTarget );// true
    console.log( this === e.target );// false
};

點擊按鈕,結果如上。

2.preventDefault()與cancelable

cancelable :只讀屬性,代表是否能夠取消事件的默認行爲,值爲true即可以,反之不行。
preventDefault :阻止特定事件的默認行爲。例如,連接的默認行爲就是在被單擊時會導航到其href特性指定的URL。

var link = document.getElementById( 'myLink' );
link.onclick = function ( e ) {
    // 阻止默認行爲
    e.preventDefault();// 只有cancelable設置爲true的事件,纔可使用
}

3.stopPropagation()與eventPhase

stopPropagation() : 取消事件進一步捕獲或冒泡,若是bubbles爲true,則可使用這個方法
eventPhase : 調用事件處理程序的階段:1.表示捕獲階段2.表示'處於目標階段'3.表示冒泡階段。

var btn = document.getElementById('myBtn');

document.body.addEventListener( 'click', function ( e ) {
    alert( e.eventPhase );
}, true );// 1

btn.addEventListener( 'click',function ( e ) {
    alert( e.eventPhase );
}, false );// 2

document.body.addEventListener( 'click', function ( e ) {
    alert( e.eventPhase );
}, false );// 3

點擊btn按鈕彈出1,2,3。

var btn = document.getElementById('myBtn');

document.body.addEventListener( 'click', function ( e ) {
    alert( e.eventPhase );// 1
}, true );

btn.addEventListener( 'click',function ( e ) {
    // 阻止進一步的事件冒泡
    e.stopPropagation();
    alert( e.eventPhase );// 2
}, false );

document.body.addEventListener( 'click', function ( e ) {
    alert( e.eventPhase );// 點擊按鈕時,事件處理程序被阻止,無反應
}, false );

點擊btn按鈕彈出1,2。

var btn = document.getElementById('myBtn');

document.body.addEventListener( 'click', function ( e ) {
    // 阻止進一步的事件冒泡
    e.stopPropagation();
    alert( e.eventPhase );// 1
}, true );

btn.addEventListener( 'click',function ( e ) {
    alert( e.eventPhase );// 點擊按鈕時,事件處理程序被阻止,無反應
}, false ); 

document.body.addEventListener( 'click', function ( e ) {
    alert( e.eventPhase );// 點擊按鈕時,事件處理程序被阻止,無反應
}, false );

點擊btn按鈕彈出1。

IE中的事件對象

訪問IE中的event對象有幾種不一樣的方式,取決於指定事件處理程序的方法。IE的event對象一樣也包含與建立它的事件相關的屬性和方法。與DOM中的event對象同樣,這些屬性和方法也會由於事件類型的不一樣而不一樣,但全部事件對象都會包含下表所列的屬性和方法。

| 屬性/方法 | 類型 | 說明
| ---------—--- | ------------- | ------------
| cancelBubble
| returnValue
| srcElement
| type

1.srcElement

事件的目標(與DOM中的target屬性相同)

var btn = document.getElementById('myBtn');

btn.onclick = function () {
    alert( window.event.srcElement === this )// true
};
btn.attachEvent('onclick', function (e) {
    alert( e.srcElement === this ) // false, IE事件處理程序綁定this的值爲window
});

2.returnValue

默認值爲true,但將其設置爲false就能夠取消事件的默認行爲(與DOM中的preventDefault()做用相同)

var link = document.getElementById( 'myLink' );
link.onclick = function () {
    // 阻止默認行爲
    window.event.returnValue = false;
}

與DOM不一樣的是,在此沒有辦法肯定事件是否能被取消。

3.cancelBubble

默認值爲false,但將其設置爲true就能夠取消事件冒泡(與DOM中的stopPropagation()做用相同)

var btn = document.getElementById('myBtn');

btn.onclick = function () {
    alert( 'Clicked' );
    window.event.cancelBubble = true;
};

document.body.onclick = function () {
    alert( 'Body Clicked' )
};

跨瀏覽器的事件對象

要訪問IE中event對象有幾種不一樣的方式,取決於指定事件處理程序的方法。在使用DOM0級方法添加事件處理程序時,event對象做爲window對象的一個屬性存在。使用IE事件處理程序,event對象能夠經過window對象進行訪問,同時也會被當作參數傳遞。

var EventUtil = {
    
    getEvent: function( event ){
        return event ? event : window.event
    }
}

事件類型

DOM3級事件模塊在DOM2級事件模塊基礎上從新定義了這些事件,也添加了一些新事件。包括IE9在內的全部主流瀏覽器都支持DOM2級事件。IE9也支持DOM3級事件。

HTML5事件

  • DOMContentLoaded :

    1. 能夠爲document和window添加相應的事件處理程序(儘管這個事件會冒泡到window,但它的目標其實是document)。

    2. DOMContentLoaded中的event對象不會提供額外的信息(其target屬性是document)
      兼容性:IE9+,Fifrefox,Chrome,Safari3.1+,Opera9+。

  • hashchange :

    1. 必需要把hashchange事件處理程添加給window對象,而後URL參數列表只要變化就會調用它。

    2. 此時的event對象應該額外包含兩個屬性:oldURL和newURL。這兩個屬性分別保存着參數列表變化先後的完整URL。
      兼容性:IE8+,firefox3.6+,Safari5+,Chrome,Opera10.6+。在這些瀏覽器中只有Firefox6+,chrome和Opera支持oldURL和newURL屬性。爲此,最好是使用location對象來肯定當前的參數列表。

鍵盤事件

  • keydown(任意鍵),keypress(字符鍵), keyup

發生keypress事件意味着按下的鍵會影響到屏幕中文本的顯示。在全部瀏覽器中,按下可以插入或者刪除字符的鍵都會觸發keypress事件。

  1. 全部元素都支持以上三個事件,但只有在用戶經過文本框輸入文本時才最經常使用到

  2. 觸發順序:在用戶按下了一個字符鍵時,keydown-->keypress-->keyup。在用戶按下的是一個非字符鍵,keydown-->keyup。

  3. event對象

    • shiftKey,ctrlKey,altKey和metaKey屬性。

    • 在發生keydown和keyup事件時,event對象的keyCode屬性會包含一個鍵碼。

兼容性:IE不支持metaKey
Working With the Keyboard

鼠標事件

  • mousedown,mouseup

  • click,dbclick

    1. 全部元素都支持鼠標事件。

    2. 觸發順序:mousedown-->mouseup-->click-->mousedown-->mouseup-->click--dbclick。在IE8以及以前版本,有一個小bug,會跳過第二個mousedown和click

    3. event對象:

      • clientX和clientY:表示事件發生時,鼠標指針在視口中的水平和垂直座標

      • PageX和PageY:表示鼠標光標在頁面中的位置,所以座標是從頁面自己,而非視口的左邊和頂邊計算的。

      • screenX和screenY:能夠肯定鼠標事件發生時,鼠標指針相對於整個屏幕的座標信息。

      • shiftKey,ctrlKey,altKey和metaKey屬性。

      • mousedown和mouseup事件,還包括一個button屬性:表示按下或釋放的按鈕DOM的button屬性可能有以下3個值,0表示主鼠標按鈕,1表示中間的鼠標按鈕,2表示次鼠標按鈕。

兼容性:

  • IE8以及更早版本不支持事件對象上的頁面座標,不過使用客戶區座標和滾動信息能夠計算出來。

  • IE8以及更早版本不支持metaKey屬性。

  • touchstart

內存和性能

事件處理程序對性能的影響

在javascript中,添加到頁面上的事件處理程序數量將直接關係到頁面的總體運行性能。

1.每一個函數(事件處理程序)都是對象,都會佔用內存。內存中的對象越多,性能就越差。
2.必須事先指定全部 事件處理程序而致使的DOM訪問次數,會延遲整個頁面的交互就緒時間。
3.每當將 事件處理程序指定給元素時,運行中的瀏覽器代碼與支持頁面交互的Javascript代碼之間就會創建一個鏈接。這種鏈接越多,頁面執行起來越慢。

<div id="love-wrapper">
    <div id="love-l">L</div>
    <div id="love-o">O</div>
    <div id="love-v">V</div>
    <div id="love-e">E</div>
</div>

var l = document.getElementById( 'love-l' );
var o = document.getElementById( 'love-o' );
var v = document.getElementById( 'love-v' );
var e = document.getElementById( 'love-e' );

l.addEventListener('click', function () {
    alert(' L ')
}, false);
o.addEventListener('click', function () {
    alert( 'O' )
}, false);
v.addEventListener('click', function () {
    alert( 'V' )
}, false);
e.addEventListener('click', function () {
    alert( 'E' )
}, false);

在上面的示例中,爲每一個元素的點擊事件都綁定了不一樣事件處理程序。

  • 取得了4個DOM元素。==>DOM訪問次數爲4次

  • 添加了4個事件處里程序。==>內存中的對象多增長了4個

  • 相應的事件處理程序與指定元素鏈接了4次==》鏈接數4

若是頁面複雜,那麼就會有數不清的代碼用於添加事件處理程序。影響頁面性能。

事件委託

對事件處理程序過多問題的解決方案就是事件委託。

事件委託利用了事件冒泡,只指定一個事件處理程序,就能夠管理 某一類型(例如:點擊事件)的全部事件。
若是可行的話,能夠考慮爲document對象添加一個事件處理程序,用以處理頁面上特定類型的事件。有點以下

  1. document對象很快就能夠訪問,並且能夠在頁面生命週期中的任什麼時候點上爲它添加事件處理程序(無需等待load和DOMContentLoaded事件)。換句話說,只要可點擊的元素呈如今頁面上,就能夠當即具有適當的功能

  2. 在頁面中設置事件處理程序所需的時間更少。只添加一個事件處理程序所需的DOM引用更少,所花的時間更少。 整個頁面所佔得內存空間更少

var love = document.getElementById( 'love-wrapper' );
love.addEventListener('click', function ( e ) {
    switch ( e.target.id ) {
        case 'love-l' : 
            alert('L');
            break;
        case 'love-o' :
            alert('O');
            break;
        case 'love-v' :
            alert('V');
            break;
        case 'love-e' :
            alert('E');
            break;
    }
},false)

在上面的示例中

  • 取得了1個DOM元素。==>DOM訪問次數減小到了1次

  • 添加了1個事件處理程序。==>內存中的對象只增長了1個

  • 相應的事件處理程序與指定元素鏈接了4次==>鏈接數1

實現了和上一個例子中同樣的效果。可是卻有效的控制了DOM訪問次數,事件處理程序的添加個數,以及DOM元素與相應的事件處理程序的鏈接次數。

移除事件處理程序

利用事件委託咱們能夠有效的控制相應的事件處理程序與指定元素的鏈接次數。另外,在不須要的時候移除事件處理程序,也是解決這個問題的一種方案。內存中留有那些過期不用的"空事件處理程序,也是形成Web應用程序內存和性能問題的主要緣由"。

有兩種狀況可能致使上述問題

  1. 帶有事件處理程序的 指定元素 經過DOM操做被刪除了,頁面中的某一部分被替換了,致使帶有事件處理程序的 指定元素 被刪除了。

  2. 卸載頁面的時候。

第一種狀況:本質上來說都是一種狀況,就是帶有事件處理程序的 指定元素被刪除了,可是其事件處理程序仍然和 指定元素保持着引用關係,致使其事件處理程序沒法被當作垃圾回收。(尤爲是IE)會作出這種處理

<div id="myDiv">
    <div id="myBtn"></div>
</div>
var handler = function () {
    // 刪除指定元素
    document.getElementById( 'myDiv' ).removeChild();
}

var btn = document.getElementById('myBtn');

btn.addEventListener('click', handler, false);

點擊按鈕時,按鈕被刪除,可是其事件處理程序卻還和其保持了引用關係,致使內存增長。所以在知道 指定元素可能被刪除的狀況下,先解除他們之間的引用關係。以下

<div id="myDiv">
    <div id="myBtn"></div>
</div>
var handler = function () {
    // 解除鏈接引用關係
    btn.removeEventListener( 'click', handler, false );

    // 刪除指定元素
    document.getElementById( 'myDiv' ).removeChild();
}

var btn = document.getElementById('myBtn');

btn.addEventListener('click', handler, false);

這樣經過解除引用鏈接關係,也能夠提高頁面性能。

第二種狀況:IE8及更早瀏覽器在這種狀況下仍然是問題最多的瀏覽器。若是在頁面卸載以前,沒有清理乾淨事件處理程序,那它們就會滯留在事件處理程序中。

通常來講,最好的作法是在頁面卸載以前,先經過unload事件處理程序移除全部事件處理程序。

相關文章
相關標籤/搜索