1事件流
    
    
        JavaScript與HTML之間的交互是通過事件實現(xiàn)的。事件,就是文檔或瀏覽器窗口中發(fā)生的一些特定的交互瞬間。可以使用偵聽器來預訂事件,以便事件發(fā)生時執(zhí)行相應的代碼。 
 
事件流的起源:就是在瀏覽器發(fā)展到第四代的時候,瀏覽器開發(fā)團隊遇到一個問題:頁面的哪一部分會擁有某個特定的事件?要明白這個問題問的是什么,可以想象畫在一張紙上的一組同心圓。如果你把手指放在圓心上,那么你的手指指向的不是一個圓,而是紙上的所有圓。也就是說如果單擊了頁面的某個按鈕,同時也單擊了按鈕的容器元素,甚至單擊了整個頁面。不過呢,IE提出的是冒泡流,而網(wǎng)景提出的是捕獲流。
    
    
        示例:
    
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>事件流</title> <style type="text/css"> #content{width: 150px;height: 150px;background-color: red;} #btn{width: 80px;height: 80px;background-color: green;} </style> </head> <body> <div id="content">content <div id="btn">button</div> </div> <script type="text/javascript"> var content = document.getElementById("content"); var btn = document.getElementById('btn');
        btn.onclick = function(){ alert("btn");
        };
        content.onclick = function(){ alert("content");
        };
        document.onclick = function(){ alert("document");
        } </script> </body> </html>
    
        - 
            1
        
 
        - 
            2
        
 
        - 
            3
        
 
        - 
            4
        
 
        - 
            5
        
 
        - 
            6
        
 
        - 
            7
        
 
        - 
            8
        
 
        - 
            9
        
 
        - 
            10
        
 
        - 
            11
        
 
        - 
            12
        
 
        - 
            13
        
 
        - 
            14
        
 
        - 
            15
        
 
        - 
            16
        
 
        - 
            17
        
 
        - 
            18
        
 
        - 
            19
        
 
        - 
            20
        
 
        - 
            21
        
 
        - 
            22
        
 
        - 
            23
        
 
        - 
            24
        
 
        - 
            25
        
 
        - 
            26
        
 
        - 
            27
        
 
        - 
            28
        
 
        - 
            29
        
 
        - 
            30
        
 
    
    
        如果點擊容器#btn,則彈出的順序是:btn-content-document;如果點擊的是容器#content,則彈出的是content-document;如果點擊的是document,彈出的是document。
    
    
        由此可以看出JavaScript的事件流機制
    
    
        前面說過,IE提出的是冒泡流,而網(wǎng)景提出的是捕獲流,后來在W3C組織的統(tǒng)一之下,JS支持了冒泡流和捕獲流,但是目前低版本的IE瀏覽器還是只能支持冒泡流(IE6,IE7,IE8均只支持冒泡流),所以為了能夠兼容更多的瀏覽器,建議大家使用冒泡流。
    
    
        JS事件流原理圖如下: 
 
 
    
    
    
        2事件冒泡與事件捕獲
    
    
        由此可以知道:
    
    
        1、一個完整的JS事件流是從window開始,最后回到window的一個過程
    
    
        2、事件流被分為三個階段(1~5)捕獲過程、(5~6)目標過程、(6~10)冒泡過程
    
    
        示例:
    
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> #wrapDiv, #innerP, #textSpan{ margin: 5px;padding: 5px;box-sizing: border-box;cursor: default; } #wrapDiv{ width: 300px;height: 300px;border: indianred 3px solid; } #innerP{ width: 200px;height: 200px;border: hotpink 3px solid; } #textSpan{ display: block;width: 100px;height: 100px;border: orange 3px solid; } </style> </head> <body> <div id="wrapDiv">wrapDiv <p id="innerP">innerP <span id="textSpan">textSpan</span> </p> </div> <script> var wrapDiv = document.getElementById("wrapDiv"); var innerP = document.getElementById("innerP"); var textSpan = document.getElementById("textSpan");  window.addEventListener("click", function(e){ console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    document.addEventListener("click", function(e){ console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    document.documentElement.addEventListener("click", function(e){ console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    document.body.addEventListener("click", function(e){ console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    innerP.addEventListener("click", function(e){ console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);
    textSpan.addEventListener("click", function(e){ console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName);
    }, true);  window.addEventListener("click", function(e){ console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    document.addEventListener("click", function(e){ console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    document.documentElement.addEventListener("click", function(e){ console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    document.body.addEventListener("click", function(e){ console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    wrapDiv.addEventListener("click", function(e){ console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    innerP.addEventListener("click", function(e){ console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false);
    textSpan.addEventListener("click", function(e){ console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName);
    }, false); </script> </body> </html>
    
        - 
            1
        
 
        - 
            2
        
 
        - 
            3
        
 
        - 
            4
        
 
        - 
            5
        
 
        - 
            6
        
 
        - 
            7
        
 
        - 
            8
        
 
        - 
            9
        
 
        - 
            10
        
 
        - 
            11
        
 
        - 
            12
        
 
        - 
            13
        
 
        - 
            14
        
 
        - 
            15
        
 
        - 
            16
        
 
        - 
            17
        
 
        - 
            18
        
 
        - 
            19
        
 
        - 
            20
        
 
        - 
            21
        
 
        - 
            22
        
 
        - 
            23
        
 
        - 
            24
        
 
        - 
            25
        
 
        - 
            26
        
 
        - 
            27
        
 
        - 
            28
        
 
        - 
            29
        
 
        - 
            30
        
 
        - 
            31
        
 
        - 
            32
        
 
        - 
            33
        
 
        - 
            34
        
 
        - 
            35
        
 
        - 
            36
        
 
        - 
            37
        
 
        - 
            38
        
 
        - 
            39
        
 
        - 
            40
        
 
        - 
            41
        
 
        - 
            42
        
 
        - 
            43
        
 
        - 
            44
        
 
        - 
            45
        
 
        - 
            46
        
 
        - 
            47
        
 
        - 
            48
        
 
        - 
            49
        
 
        - 
            50
        
 
        - 
            51
        
 
        - 
            52
        
 
        - 
            53
        
 
        - 
            54
        
 
        - 
            55
        
 
        - 
            56
        
 
        - 
            57
        
 
        - 
            58
        
 
        - 
            59
        
 
        - 
            60
        
 
        - 
            61
        
 
        - 
            62
        
 
        - 
            63
        
 
        - 
            64
        
 
        - 
            65
        
 
        - 
            66
        
 
        - 
            67
        
 
        - 
            68
        
 
        - 
            69
        
 
        - 
            70
        
 
        - 
            71
        
 
        - 
            72
        
 
        - 
            73
        
 
        - 
            74
        
 
        - 
            75
        
 
        - 
            76
        
 
        - 
            77
        
 
        - 
            78
        
 
        - 
            79
        
 
        - 
            80
        
 
        - 
            81
        
 
        - 
            82
        
 
        - 
            83
        
 
        - 
            84
        
 
        - 
            85
        
 
        - 
            86
        
 
        - 
            87
        
 
        - 
            88
        
 
        - 
            89
        
 
        - 
            90
        
 
        - 
            91
        
 
    
    
        這個時候,如果點擊一下textSpan這個元素,控制臺會打印出這樣的內(nèi)容: 
 
    
    
        從上面所畫的事件傳播的過程能夠看出來,當點擊鼠標后,會先發(fā)生事件的捕獲
    
    
        · 捕獲階段:首先window會獲捕獲到事件,之后document、documentElement、body會捕獲到,再之后就是在body中DOM元素一層一層的捕獲到事件,有wrapDiv、innerP。
    
    
        · 目標階段:真正點擊的元素textSpan的事件發(fā)生了兩次,因為在上面的JavaScript代碼中,textSapn既在捕獲階段綁定了事件,又在冒泡階段綁定了事件,所以發(fā)生了兩次。但是這里有一點是需要注意,在目標階段并不一定先發(fā)生在捕獲階段所綁定的事件,而是先綁定的事件發(fā)生,一會會解釋一下。
    
    
        · 冒泡階段:會和捕獲階段相反的步驟將事件一步一步的冒泡到window
    
    
        上述代碼中的兩個屬性:e.target和e.currentTarget
    
    
        target和currentTarget都是event上面的屬性,target是真正發(fā)生事件的DOM元素,而currentTarget是當前事件發(fā)生在哪個DOM元素上。
    
    
        可以結合控制臺打印出來的信息理解下,目標階段也就是 target == currentTarget的時候。我沒有打印它們兩個因為太長了,所以打印了它們的nodeName,但是由于window沒有nodeName這個屬性,所以是undefined。
    
    
        那可能有一個疑問,我們不用addEventListener綁定的事件會發(fā)生在哪個階段呢,我們來一個測試,順便再演示一下我在上面的目標階段所說的目標階段并不一定先發(fā)生捕獲階段所綁定的事件是怎么一回事。
    
<script>
    var wrapDiv = document.getElementById("wrapDiv") var innerP = document.getElementById("innerP") var textSpan = document.getElementById("textSpan") // 測試直接綁定的事件到底發(fā)生在哪個階段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 測試直接綁定的事件到底發(fā)生在哪個階段")
    } // 捕獲階段綁定事件
    window.addEventListener("click", function(e){
        console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.addEventListener("click", function(e){
        console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.body.addEventListener("click", function(e){
        console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) innerP.addEventListener("click", function(e){
        console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) textSpan.addEventListener("click", function(){
        console.log("textSpan 冒泡 在捕獲之前綁定的")
    }, false) textSpan.onclick = function(){
        console.log("textSpan onclick")
    } textSpan.addEventListener("click", function(e){
        console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) // 冒泡階段綁定的事件
    window.addEventListener("click", function(e){
        console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.addEventListener("click", function(e){
        console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.body.addEventListener("click", function(e){
        console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) innerP.addEventListener("click", function(e){
        console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) textSpan.addEventListener("click", function(e){
        console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) </script>
    
        - 
            1
        
 
        - 
            2
        
 
        - 
            3
        
 
        - 
            4
        
 
        - 
            5
        
 
        - 
            6
        
 
        - 
            7
        
 
        - 
            8
        
 
        - 
            9
        
 
        - 
            10
        
 
        - 
            11
        
 
        - 
            12
        
 
        - 
            13
        
 
        - 
            14
        
 
        - 
            15
        
 
        - 
            16
        
 
        - 
            17
        
 
        - 
            18
        
 
        - 
            19
        
 
        - 
            20
        
 
        - 
            21
        
 
        - 
            22
        
 
        - 
            23
        
 
        - 
            24
        
 
        - 
            25
        
 
        - 
            26
        
 
        - 
            27
        
 
        - 
            28
        
 
        - 
            29
        
 
        - 
            30
        
 
        - 
            31
        
 
        - 
            32
        
 
        - 
            33
        
 
        - 
            34
        
 
        - 
            35
        
 
        - 
            36
        
 
        - 
            37
        
 
        - 
            38
        
 
        - 
            39
        
 
        - 
            40
        
 
        - 
            41
        
 
        - 
            42
        
 
        - 
            43
        
 
        - 
            44
        
 
        - 
            45
        
 
        - 
            46
        
 
        - 
            47
        
 
        - 
            48
        
 
        - 
            49
        
 
        - 
            50
        
 
        - 
            51
        
 
        - 
            52
        
 
        - 
            53
        
 
        - 
            54
        
 
        - 
            55
        
 
        - 
            56
        
 
        - 
            57
        
 
        - 
            58
        
 
        - 
            59
        
 
        - 
            60
        
 
        - 
            61
        
 
        - 
            62
        
 
        - 
            63
        
 
        - 
            64
        
 
        - 
            65
        
 
        - 
            66
        
 
        - 
            67
        
 
        - 
            68
        
 
        - 
            69
        
 
        - 
            70
        
 
        - 
            71
        
 
        - 
            72
        
 
        - 
            73
        
 
        - 
            74
        
 
        - 
            75
        
 
        - 
            76
        
 
    
    
        控制臺打印如下:
    
    
        
    
    
        · textSpan是被點擊的元素,也就是目標元素,所有在textSpan上綁定的事件都會發(fā)生在目標階段,在綁定捕獲代碼之前寫了綁定的冒泡階段的代碼,所以在目標元素上就不會遵守先發(fā)生捕獲后發(fā)生冒泡這一規(guī)則,而是先綁定的事件先發(fā)生。 
    
    
        [在目標元素上就不會遵守先發(fā)生捕獲后發(fā)生冒泡這一規(guī)則,而是先綁定的事件先發(fā)生。]
    
    
        · 由于wrapDiv不是目標元素,所以它上面綁定的事件會遵守先發(fā)生捕獲后發(fā)生冒泡的規(guī)則。所以很明顯用onclick直接綁定的事件發(fā)生在了冒泡階段。
    
    
    
        3事件綁定
    
    
        1、直接獲取元素綁定:
    
element.onclick = function(e){
        // ... };
    
    
        優(yōu)點:簡單和穩(wěn)定,可以確保它在你使用的不同瀏覽器中運作一致;處理事件時,this關鍵字引用的是當前元素,這很有幫助。
    
    
        缺點:只會在事件冒泡中運行;一個元素一次只能綁定一個事件處理函數(shù),新綁定的事件處理函數(shù)會覆蓋舊的事件處理函數(shù);事件對象參數(shù)(e)僅非IE瀏覽器可用。
    
    
    
        2、直接在元素里面使用事件屬性
    
    
        3、W3C方法:
    
element.addEventListener('click', function(e){
        // ... }, false);
    
    
        優(yōu)點:該方法同時支持事件處理的捕獲和冒泡階段;事件階段取決于addEventListener最后的參數(shù)設置:false (冒泡) 或 true (捕獲);在事件處理函數(shù)內(nèi)部,this關鍵字引用當前元素;事件對象總是可以通過處理函數(shù)的第一個參數(shù)(e)捕獲;可以為同一個元素綁定你所希望的多個事件,同時并不會覆蓋先前綁定的事件
    
    
        缺點:IE不支持,你必須使用IE的attachEvent函數(shù)替代。
    
    
    
        IE下的方法:
    
element.attachEvent('onclick', function(){
        // ... });
    
    
        優(yōu)點:可以為同一個元素綁定你所希望的多個事件,同時并不會覆蓋先前綁定的事件。 
 
缺點:IE僅支持事件捕獲的冒泡階段;事件監(jiān)聽函數(shù)內(nèi)的this關鍵字指向了window對象,而不是當前元素(IE的一個巨大缺點);事件對象僅存在與window.event參數(shù)中;事件必須以ontype的形式命名,比如,onclick而非click;僅IE可用,你必須在非IE瀏覽器中使用W3C的addEventListener。
    
    
        注意:不是意味這低版本的ie沒有事件捕獲,它也是先發(fā)生事件捕獲,再發(fā)生事件冒泡,只不過這個過程無法通過程序控制。 
    
    
    
        4解除事件
    
    
        通用:
    
element.removeEventListener('click', function(e){
        // ... }, false);
    
    
        IE:
    
element.detachEvent('onclick', function(){
        // ... });
    
    
    
        5阻止事件傳播
    
    
        在支持addEventListener()的瀏覽器中,可以調(diào)用事件對象的stopPropagation()方法以阻止事件的繼續(xù)傳播。如果在同一對象上定義了其他處理程序,剩下的處理程序?qū)⒁琅f被調(diào)用,但調(diào)用stopPropagation()之后任何其他對象上的事件處理程序?qū)⒉粫徽{(diào)用。不僅可以阻止事件在冒泡階段的傳播,還能阻止事件在捕獲階段的傳播。
    
    
        IE9之前的IE不支持stopPropagation()方法,而是設置事件對象cancelBubble屬性為true來實現(xiàn)阻止事件進一步傳播。
    
<script>
    var wrapDiv = document.getElementById("wrapDiv") var innerP = document.getElementById("innerP") var textSpan = document.getElementById("textSpan") // 測試直接綁定的事件到底發(fā)生在哪個階段
    wrapDiv.onclick = function(){
        console.log("wrapDiv onclick 測試直接綁定的事件到底發(fā)生在哪個階段")
    } // 捕獲階段綁定事件
    window.addEventListener("click", function(e){
        console.log("window 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.addEventListener("click", function(e){
        console.log("document 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) document.body.addEventListener("click", function(e){
        console.log("body 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 捕獲", e.target.nodeName, e.currentTarget.nodeName) // 在捕獲階段阻止事件的傳播
        e.stopPropagation() }, true) innerP.addEventListener("click", function(e){
        console.log("innerP 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) textSpan.addEventListener("click", function(){
        console.log("textSpan 冒泡 在捕獲之前綁定的")
    }, false) textSpan.onclick = function(){
        console.log("textSpan onclick")
    } textSpan.addEventListener("click", function(e){
        console.log("textSpan 捕獲", e.target.nodeName, e.currentTarget.nodeName) }, true) // 冒泡階段綁定的事件
    window.addEventListener("click", function(e){
        console.log("window 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.addEventListener("click", function(e){
        console.log("document 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.documentElement.addEventListener("click", function(e){
        console.log("documentElement 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) document.body.addEventListener("click", function(e){
        console.log("body 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) wrapDiv.addEventListener("click", function(e){
        console.log("wrapDiv 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) innerP.addEventListener("click", function(e){
        console.log("innerP 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) textSpan.addEventListener("click", function(e){
        console.log("textSpan 冒泡", e.target.nodeName, e.currentTarget.nodeName) }, false) </script>
    
        - 
            1
        
 
        - 
            2
        
 
        - 
            3
        
 
        - 
            4
        
 
        - 
            5
        
 
        - 
            6
        
 
        - 
            7
        
 
        - 
            8
        
 
        - 
            9
        
 
        - 
            10
        
 
        - 
            11
        
 
        - 
            12
        
 
        - 
            13
        
 
        - 
            14
        
 
        - 
            15
        
 
        - 
            16
        
 
        - 
            17
        
 
        - 
            18
        
 
        - 
            19
        
 
        - 
            20
        
 
        - 
            21
        
 
        - 
            22
        
 
        - 
            23
        
 
        - 
            24
        
 
        - 
            25
        
 
        - 
            26
        
 
        - 
            27
        
 
        - 
            28
        
 
        - 
            29
        
 
        - 
            30
        
 
        - 
            31
        
 
        - 
            32
        
 
        - 
            33
        
 
        - 
            34
        
 
        - 
            35
        
 
        - 
            36
        
 
        - 
            37
        
 
        - 
            38
        
 
        - 
            39
        
 
        - 
            40
        
 
        - 
            41
        
 
        - 
            42
        
 
        - 
            43
        
 
        - 
            44
        
 
        - 
            45
        
 
        - 
            46
        
 
        - 
            47
        
 
        - 
            48
        
 
        - 
            49
        
 
        - 
            50
        
 
        - 
            51
        
 
        - 
            52
        
 
        - 
            53
        
 
        - 
            54
        
 
        - 
            55
        
 
        - 
            56
        
 
        - 
            57
        
 
        - 
            58
        
 
        - 
            59
        
 
        - 
            60
        
 
        - 
            61
        
 
        - 
            62
        
 
        - 
            63
        
 
        - 
            64
        
 
        - 
            65
        
 
        - 
            66
        
 
        - 
            67
        
 
        - 
            68
        
 
        - 
            69
        
 
        - 
            70
        
 
        - 
            71
        
 
        - 
            72
        
 
        - 
            73
        
 
        - 
            74
        
 
        - 
            75
        
 
        - 
            76
        
 
        - 
            77
        
 
        - 
            78
        
 
    
    
        
    
    
        實際上我們點擊的是textSpan,但是由于在捕獲階段事件就被阻止了傳播,所以在textSpan上綁定的事件根本就沒有發(fā)生,冒泡階段綁定的事件自然也不會發(fā)生,因為阻止事件在捕獲階段傳播的特性,e.stopPropagation()很少用到在捕獲階段去阻止事件的傳播,大家就以為e.stopPropagation()只能阻止事件在冒泡階段傳播。 
    
    
    
        6阻止事件的默認行為
    
    
        e.preventDefault()可以阻止事件的默認行為發(fā)生,默認行為是指:點擊a標簽就轉(zhuǎn)跳到其他頁面、拖拽一個圖片到瀏覽器會自動打開、點擊表單的提交按鈕會提交表單等等,因為有的時候我們并不希望發(fā)生這些事情,所以需要阻止默認行為。
    
    
        IE9之前的IE中,可以通過設置事件對象的returnValue屬性為false達到同樣的效果。
    
function cancelHandler(event){ var event=event||window.event;  if(event.preventDefault)  event.preventDefault(); if(event.returnValue)  event.returnValue=false; return false;  }
    
    
    
        7事件委托
    
    
        在JavaScript中,添加到頁面上的事件處理程序數(shù)量將直接關系到頁面的整體運行性能。導致這一問題的原因是多方面的。首先,每個函數(shù)都是對象,都會占用內(nèi)存;內(nèi)存中的對象越多,性能就越差。其次,必須事先指定所有事件處理程序而導致的DOM訪問次數(shù),會延遲整個頁面的交互就緒時間。
    
    
        對“事件處理程序過多”問題的解決方案就是事件委托。事件委托利用了事件冒泡,只指定一個事件處理程序,就可以管理某一類型的所有事件。例如,click事件會一直冒泡到document層次。也就是說,我們可以為整個頁面指定一個onclick事件處理程序,而不必給每個可單擊的元素分別添加事件處理程序。
    
    
        在父級上定義了函數(shù),當點擊目標時,會向上冒泡,到父級執(zhí)行操作。每一個子元素,都會統(tǒng)一冒泡到父級然后執(zhí)行。
    
<ul id="color-list"> <li>red</li> <li>yellow</li> <li>blue</li> <li>green</li> <li>black</li> <li>white</li> </ul>
    
    
        如果點擊頁面中的li元素,然后輸出li當中的顏色,我們通常會這樣寫:
    
(function(){
    var color_list = document.getElementById('color-list') var colors = color_list.getElementsByTagName('li') for(var i=0 colors[i].addEventListener('click',showColor,false) } function showColor(e){
        var x = e.target alert("The color is " + x.innerHTML) } })()
    
    
        利用事件流的特性,我們只綁定一個事件處理函數(shù)也可以完成:
    
(function(){
    var color_list = document.getElementById('color-list') color_list.addEventListener('click',showColor,false) function showColor(e){
        var x = e.target if(x.nodeName.toLowerCase() === 'li'){
            alert('The color is ' + x.innerHTML) } } })()
    
    
        事件委托還有一個好處就是添加進來的元素也能綁定事件:
    
    
        沒有使用事件委托:
    
<body> <ul id="thl"> <li>001</li> <li>002</li> <li>003</li> </ul> <button onclick="fun()">touch</button> <script> var thl= document.getElementById('thl'); var aLi = thl.getElementsByTagName('li'); for (var i = 0; i < aLi.length; i++) {
      aLi[i].onclick = fn;
    } function fn (){ console.log(this.innerHTML);
    } function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
        node.appendChild(textnode);
        document.getElementById("thl").appendChild(node);
    } </script> </body>
    
        - 
            1
        
 
        - 
            2
        
 
        - 
            3
        
 
        - 
            4
        
 
        - 
            5
        
 
        - 
            6
        
 
        - 
            7
        
 
        - 
            8
        
 
        - 
            9
        
 
        - 
            10
        
 
        - 
            11
        
 
        - 
            12
        
 
        - 
            13
        
 
        - 
            14
        
 
        - 
            15
        
 
        - 
            16
        
 
        - 
            17
        
 
        - 
            18
        
 
        - 
            19
        
 
        - 
            20
        
 
        - 
            21
        
 
        - 
            22
        
 
        - 
            23
        
 
        - 
            24
        
 
        - 
            25
        
 
        - 
            26
        
 
        - 
            27
        
 
    
    
        使用了事件委托:
    
<script> var thl= document.getElementById('thl');
    thl.onclick = function(ev) { ev = ev || event;  var target = ev.target || ev.srcElement;  if (target.nodeName.toLowerCase() == 'li') {
              console.log(target.innerHTML);
         }
    }; function fun(){ var node=document.createElement("li"); var textnode=document.createTextNode("maomaoliang");
        node.appendChild(textnode);
        document.getElementById("thl").appendChild(node);
    } </script>
藍藍設計( m.wnxcall.com )是一家專注而深入的界面設計公司,為期望卓越的國內(nèi)外企業(yè)提供卓越的UI界面設計、BS界面設計 、 cs界面設計 、 ipad界面設計 、 包裝設計 、 圖標定制 、 用戶體驗 、交互設計、 網(wǎng)站建設 、平面設計服務