事件:
JavaScript 和 HTML的交互是通過(guò)事件實(shí)現(xiàn)的。
事件是某個(gè)行為或者觸發(fā),比如點(diǎn)擊、鼠標(biāo)移動(dòng):
- 當(dāng)用戶點(diǎn)擊鼠標(biāo)時(shí)
- 當(dāng)網(wǎng)頁(yè)已加載時(shí)
- 當(dāng)圖像已加載時(shí)
- 當(dāng)鼠標(biāo)移動(dòng)到元素上時(shí)
- 當(dāng)用戶觸發(fā)按鍵時(shí)
事件流
-
事件冒泡
事件開(kāi)始時(shí)由最具體的元素接受,然后逐級(jí)向上傳播到較為不具體的元素
-
事件捕獲
不太具體的節(jié)點(diǎn)更早接受事件,而最具體的元素最后接受事件,和事件冒泡相反
-
DOM事件流
DOM2級(jí)事件規(guī)定事件流包括三個(gè)階段,事件捕獲階段,處于目標(biāo)階段,時(shí)間冒泡階段,首先發(fā)生的是事件捕獲,為截取事件提供機(jī)會(huì),然后是實(shí)際目標(biāo)接受事件,最后是冒泡階段
注:Opera、Firefox、Sarfari都支持DOM事件流,IE不支持事件流,只支持時(shí)間冒泡
事件傳播機(jī)制
當(dāng)一個(gè)事件發(fā)生以后,它會(huì)在不同的DOM節(jié)點(diǎn)之間傳播(propagation)。這種傳播分為三個(gè)階段:

- 第一階段:從window對(duì)象傳導(dǎo)到目標(biāo)節(jié)點(diǎn),稱(chēng)為“捕獲階段”(capture phase)。
- 第二階段:在目標(biāo)節(jié)點(diǎn)上觸發(fā),稱(chēng)為“目標(biāo)階段”(target phase)。
- 第三階段:從目標(biāo)節(jié)點(diǎn)傳導(dǎo)回window對(duì)象,稱(chēng)為“冒泡階段”(bubbling phase)。
這種三階段的傳播模型,會(huì)使得一個(gè)事件在多個(gè)節(jié)點(diǎn)上觸發(fā)。
比如:
<div>
<p>Click Me</p>
</div>
如果對(duì)這兩個(gè)節(jié)點(diǎn)的click事件都設(shè)定監(jiān)聽(tīng)函數(shù),則click事件會(huì)被觸發(fā)四次。<div>和<p>節(jié)點(diǎn)的捕獲階段和冒泡階段各一次:
- 捕獲階段:事件從
<div>向<p>傳播時(shí),觸發(fā)<div>的click事件; - 目標(biāo)階段:事件從
<div>到達(dá)<p>時(shí),觸發(fā)<p>的click事件; - 目標(biāo)階段:事件離開(kāi)
<p>時(shí),觸發(fā)<p>的click事件; - 冒泡階段:事件從
<p>傳回<div>時(shí),再次觸發(fā)<div>的click事件。
用戶點(diǎn)擊網(wǎng)頁(yè)的時(shí)候,瀏覽器總是假定click事件的目標(biāo)節(jié)點(diǎn),就是點(diǎn)擊位置的嵌套最深的那個(gè)節(jié)點(diǎn)。所以<p>節(jié)點(diǎn)的捕獲和冒泡階段都會(huì)顯示為target階段。
event.stopPropagation()
stopPropagation方法阻止事件在DOM中繼續(xù)傳播,即取消進(jìn)一步的事件捕獲或冒泡,防止再觸發(fā)定義在別的節(jié)點(diǎn)上的監(jiān)聽(tīng)函數(shù),但是不包括在當(dāng)前節(jié)點(diǎn)上新定義的事件監(jiān)聽(tīng)函數(shù)。
我們可以在button的事件處理程序中調(diào)用stopPropagation()從而避免注冊(cè)在body上的事件發(fā)生。
var handler = function(e){
alert(e.type);
e.stopPropagation();
}
addEvent(document.body, 'click', function(){alert('Clicked body')});
var btnClick = document.getElementById('btnClick');
addEvent(btnClick, 'click', handler);
//若是注釋掉e.stopPropagation();在點(diǎn)擊button的時(shí)候,由于事件冒泡,body的click事件也會(huì)觸發(fā),但是調(diào)用后這句后,事件會(huì)停止傳播。
event.preventDefault()
preventDafault方法取消瀏覽器對(duì)當(dāng)前事件的默認(rèn)行為,比如點(diǎn)擊鏈接后,瀏覽器跳轉(zhuǎn)到指定頁(yè)面,或者按一下空格鍵,頁(yè)面向下滾動(dòng)一段距離。該方法生效的前提是,事件的cancelable屬性為true如果為fales,則調(diào)用該方法沒(méi)有任何效果。
該方法不會(huì)阻止事件的進(jìn)一步傳播(stopPropagation方法可用于這個(gè)目的)。只要在事件的傳播過(guò)程中使用了preventDefault方法,該事件的默認(rèn)方法就不會(huì)執(zhí)行。
//html代碼為
//<input type="checkbox" id="my-checkbox"/>
var cb = document.getElementById('my-checkbox');
cb.addEventListener('click', function(e){
e.preventDafault();
},);
上面代碼為點(diǎn)擊單選框事件,設(shè)置監(jiān)聽(tīng)函數(shù),取消默認(rèn)行為。由于瀏覽器的默認(rèn)行為是選中單選框,所以這段代碼會(huì)導(dǎo)致無(wú)法選中單選框。
利用這個(gè)方法,可以為文本輸入框設(shè)置校驗(yàn)條件。如果用戶的輸入不符合條件,就無(wú)法將字符輸入文本框。
function checkName(e){
if(e.charCode < 97 || e.charCode > 122){
e.preventDafault();
}
}
//keypress監(jiān)聽(tīng)函數(shù),只能輸入小寫(xiě)字母,否則輸入事件的默認(rèn)事件(寫(xiě)入文本框)將本取消。
如果監(jiān)聽(tīng)函數(shù)最后返回布爾值false(return false),瀏覽器也不會(huì)觸發(fā)默認(rèn)行為,與preventDafault方法有等同效果。
事件代理
由于事件會(huì)在冒泡階段向上傳播到父節(jié)點(diǎn),因此可以把子節(jié)點(diǎn)的監(jiān)聽(tīng)函數(shù)統(tǒng)一處理多個(gè)子元素的事件。這種方法叫做事件的代理
定義:事件代理就是利用事件冒泡,只指定一個(gè)事件處理程序,就可以管理某一類(lèi)型的所有事件。(delegation)。
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event){
if(event.target.tagName.toLowerCase() === 'li'){
//...
}
})
上面代碼的click事件的監(jiān)聽(tīng)函數(shù)定義在<ul>節(jié)點(diǎn),但是實(shí)際上,它處理額是子節(jié)點(diǎn)<li>的click事件。這樣的好處是,只要定義一個(gè)監(jiān)聽(tīng)函數(shù),就能處理多個(gè)子節(jié)點(diǎn)的事件,且以后再添加子節(jié)點(diǎn),監(jiān)聽(tīng)函數(shù)依然有效。
寫(xiě)一個(gè) Demo,演示事件傳播的過(guò)程,演示阻止傳播的效果
- 事件傳播
//html部分
<body>
<style>
* {
padding: 10px;
margin: 0;
}
.box,
.container,
.target {
border: 1px solid;
}
</style>
<div class="box">box
<div class="container">container
<div class="target">
target
</div>
</div>
</div>
</body>
//js部分
<script>
//為了減少代碼量,寫(xiě)一個(gè)$函數(shù)
function $(selector){
return document.querySelector(selector);
}
$('.box').addEventListener('click', function(e){
console.log('box click...in 捕獲階段');
}, true);
$('.container').addEventListener('click', function(e){
console.log('container click...in 捕獲階段');
}, true);
$('.target').addEventListener('click',function(e){
console.log('target click...in 捕獲階段');
}, true);
$('.target').addEventListener('click', function(e){
console.log('target click...in 冒泡階段');
}, false);
$('.container').addEventListener('click', function(e){
console.log('container click...in 冒泡階段');
}, false);
$('.box').addEventListener('click', function(e){
console.log('box click...in 冒泡階段');
}, false);
</script>

事件傳播預(yù)覽地址
- 阻止事件傳播
點(diǎn)擊target時(shí)發(fā)現(xiàn)在container捕獲階段時(shí)事件被阻止傳播了
阻止事件傳播預(yù)覽




