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
