JS事件流模型
事件捕獲Event Capturing
是一種從上而下的傳播方式,以click
事件為例,其會從最外層根節向內傳播到達點擊的節點,為從最外層節點逐漸向內傳播直到目標節點的方式。
事件冒泡Event Bubbling
是一種從下往上的傳播方式,同樣以click
事件為例,事件最開始由點擊的節點,然后逐漸向上傳播直至最高層節點。
DOM0級模型
也稱為原始事件模型,這種方式較為簡單且兼容所有瀏覽器,但是卻將界面與邏輯耦合在一起,可維護性差。
實例
當點擊id
為i3
的<div>
時,瀏覽器會依次彈出2 1 0
。
<!DOCTYPE html>
<html>
<head>
<title>JS事件流模型</title>
</head>
<style type="text/css">
div{
display: flex;
justify-content: center;
align-items: center;
}
</style>
<body>
<div id="i1" style="height: 150px;width: 150px;background: red;" onclick="alert(0)">
<div id="i2" style="height: 100px;width: 100px;background: green;" onclick="alert(1)">
<div id="i3" style="height: 50px;width: 50px;background: blue;" onclick="alert(2)"></div>
</div>
</div>
</body>
</html>
IE事件模型
IE8
及之前的版本是不支持捕獲事件的,IE
事件模型共有兩個過程:
事件處理階段target phase
,事件到達目標元素, 觸發目標元素的監聽事件。
事件冒泡階段bubbling phase
事件從目標元素冒泡到document
,依次執行經過的節點綁定的事件。
DOM2級模型
DOM2
事件模型是W3C
制定的標准模型,支持捕獲型事件和冒泡型事件,調用事件的處理階段依次為捕獲、目標、冒泡。
實例
當點擊id
為i3
的<div>
時,瀏覽器會依次彈出0 1 3 2
,addEventListener
方法的第三個參數為聲明綁定的事件為捕獲型還是冒泡型,默認為false
,也就是冒泡型。
<!DOCTYPE html>
<html>
<head>
<title>JS事件流模型</title>
</head>
<style type="text/css">
div{
display: flex;
justify-content: center;
align-items: center;
}
</style>
<body>
<div id="i1" style="height: 150px;width: 150px;background: red;">
<div id="i2" style="height: 100px;width: 100px;background: green;">
<div id="i3" style="height: 50px;width: 50px;background: blue;"></div>
</div>
</div>
</body>
<script type="text/javascript">
document.addEventListener('click',(e) => {
alert(0);
},true)
document.getElementById("i1").addEventListener('click',(e) => {
alert(1);
},true)
document.getElementById("i2").addEventListener('click',(e) => {
alert(2);
})
document.getElementById("i3").addEventListener('click',(e) => {
alert(3);
})
</script>
</html>
document
對象與i1
節點綁定的是捕獲型的監聽事件,i2
與i3
節點綁定的是冒泡型的事件,事件傳遞的順序為:
window --- document --- html --- body --- i1 --- i2 --- i3 --- i2 --- i1 --- body --- html --- document --- window
從window
到i3
的過程為捕獲階段,依次執行了過程中綁定的事件,本例中執行了alert(0)
與alert(1)
,然后到達目標階段的i3
,執行i3
綁定的事件alert(3)
,然后從i3
到window
的階段為冒泡階段,執行了綁定的alert(2)
,執行順序即為0 1 3 2
。
注意
綁定監聽事件使用的區別
在DOM0
中直接綁定函數執行時,后定義的函數會覆蓋前邊綁定的函數,下面這個例子只執行alert(1)
而不執行alert(0)
。click()
是一個對象事件,點擊即觸發onclick()
綁定的方法,onclick()
是對象的屬性,將其綁定函數后即為click()
事件觸發后執行的方法。
<!DOCTYPE html>
<html>
<head>
<title>JS事件流模型</title>
</head>
<style type="text/css">
div{
display: flex;
justify-content: center;
align-items: center;
}
</style>
<body>
<div id="i1" style="height: 150px;width: 150px;background: red;"></div>
</body>
<script type="text/javascript">
document.getElementById("i1").onclick = function(){
alert(0);
} // 被覆蓋
document.getElementById("i1").onclick = function(){
alert(1);
} // 執行
</script>
</html>
addEventListener
可以為事件綁定多個函數,並且綁定時不需要加on
,其還可以接收第三個參數useCapture
來決定事件時綁定的捕獲階段還是冒泡階段執行。
document.getElementById("i1").addEventListener('click',(e) => {
alert(0);
}) // 執行
document.getElementById("i1").addEventListener('click',(e) => {
alert(1);
}) // 執行
attachEvent
可以為事件綁定多個函數,綁定時需要加on
,其只支持冒泡階段執行,所以不存在第三個參數。
document.getElementById("i1").attachEvent('onclick',function(e){
alert(0);
}) // 執行
document.getElementById("i1").attachEvent('onclick',function(e){
alert(1);
}) // 執行
每日一題
https://github.com/WindrunnerMax/EveryDay