1. 程式人生 > >JavaScript中DOM樹的事件流

JavaScript中DOM樹的事件流

圖片展示了DOM樹是如何使用事件流進行事件分發:


Dom樹中從最外層的Window至內層具體的html標籤都可以通過addEventListener(type, listener, useCapture)方法新增監聽事件。

捕獲階段(Capture Phase):

事件分發順序是從最外層的Window開始,按照順序:Window-Document-html-body-table-tbody-tr-td由外至內分發。

目標階段(Target Phase):

事件分發至真正被點選的元素。

冒泡階段(Bubbling Phase):

事件分發順序是從最內層的td開始,按照順序:td-tr-tbody-table-body-html-Document-Window由內往外分發,與事件捕獲順序相反。就像將一個石頭扔進水裡,氣泡由水底向水面上浮一樣。


例子:


<style>
	    #testDiv, #testP, #testSpan{
	        margin: 5px;
	        padding: 5px;
	        box-sizing: border-box;
	        cursor: default;
	    }
	    #testDiv{
	        width: 300px;
	        height: 300px;
	        border: indianred 3px solid;
	    }
	    #testP{
	        width: 200px;
	        height: 200px;
	        border: hotpink 3px solid;
	    }
	    #testSpan{
	        display: block;
	        width: 100px;
	        height: 100px;
	        border: orange 3px solid;
	    }
</style>
<body>
    <div id="testDiv">testDiv
        <p id="testP">testP
            <span id="testSpan">testSpan</span>
        </p>
    </div>
</body>

<script>
    var testDiv = document.getElementById("testDiv");
    var testP = document.getElementById("testP");
    var testSpan = document.getElementById("testSpan");

    // 捕獲,階段繫結事件
    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("html 捕獲,", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, true);

    document.body.addEventListener("click", function(e){
        console.log("body 捕獲,", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, true);

    testDiv.addEventListener("click", function(e){
        console.log("testDiv 捕獲,", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, true);

    testP.addEventListener("click", function(e){
        console.log("testP 捕獲,,", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, true);

    testSpan.addEventListener("click", function(e){
        console.log("testSpan 捕獲,", "目標節點:" + 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("html 冒泡", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, false);

    document.body.addEventListener("click", function(e){
        console.log("body 冒泡", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, false);

    testDiv.addEventListener("click", function(e){
        console.log("testDiv 冒泡", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, false);

    testP.addEventListener("click", function(e){
        console.log("testP 冒泡", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, false);

    testSpan.addEventListener("click", function(e){
        console.log("testSpan 冒泡", "目標節點:" + e.target.nodeName, ", 當前節點:" + e.currentTarget.nodeName);
    }, false);
</script>
點選testSpan標籤佈局的橙色方框內部,控制檯的列印結果如下: