事件:
JavaScript 和 HTML的交互是通過事件實(shí)現(xiàn)的局待。
事件是某個(gè)行為或者觸發(fā),比如點(diǎn)擊、鼠標(biāo)移動(dòng):
- 當(dāng)用戶點(diǎn)擊鼠標(biāo)時(shí)
- 當(dāng)網(wǎng)頁已加載時(shí)
- 當(dāng)圖像已加載時(shí)
- 當(dāng)鼠標(biāo)移動(dòng)到元素上時(shí)
- 當(dāng)用戶觸發(fā)按鍵時(shí)
事件流
-
事件冒泡
事件開始時(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),稱為“捕獲階段”(capture phase)拓萌。
- 第二階段:在目標(biāo)節(jié)點(diǎn)上觸發(fā),稱為“目標(biāo)階段”(target phase)升略。
- 第三階段:從目標(biāo)節(jié)點(diǎn)傳導(dǎo)回window對(duì)象微王,稱為“冒泡階段”(bubbling phase)。
這種三階段的傳播模型品嚣,會(huì)使得一個(gè)事件在多個(gè)節(jié)點(diǎn)上觸發(fā)炕倘。
比如:
<div>
<p>Click Me</p>
</div>
如果對(duì)這兩個(gè)節(jié)點(diǎn)的click
事件都設(shè)定監(jiān)聽函數(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)階段:事件離開
<p>
時(shí),觸發(fā)<p>
的click
事件逝撬; - 冒泡階段:事件從
<p>
傳回<div>
時(shí)浴骂,再次觸發(fā)<div>
的click
事件。
用戶點(diǎn)擊網(wǎng)頁的時(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)聽函數(shù),但是不包括在當(dāng)前節(jié)點(diǎn)上新定義的事件監(jiān)聽函數(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)到指定頁面份氧,或者按一下空格鍵,頁面向下滾動(dòng)一段距離弯屈。該方法生效的前提是蜗帜,事件的cancelable
屬性為true
如果為fales
,則調(diào)用該方法沒有任何效果资厉。
該方法不會(huì)阻止事件的進(jìn)一步傳播(stopPropagation方法可用于這個(gè)目的)厅缺。只要在事件的傳播過程中使用了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)聽函數(shù),取消默認(rèn)行為窄刘。由于瀏覽器的默認(rèn)行為是選中單選框窥妇,所以這段代碼會(huì)導(dǎo)致無法選中單選框。
利用這個(gè)方法娩践,可以為文本輸入框設(shè)置校驗(yàn)條件活翩。如果用戶的輸入不符合條件,就無法將字符輸入文本框翻伺。
function checkName(e){
if(e.charCode < 97 || e.charCode > 122){
e.preventDafault();
}
}
//keypress監(jiān)聽函數(shù)材泄,只能輸入小寫字母,否則輸入事件的默認(rèn)事件(寫入文本框)將本取消穆趴。
如果監(jiān)聽函數(shù)最后返回布爾值false(return false)脸爱,瀏覽器也不會(huì)觸發(fā)默認(rèn)行為,與preventDafault方法有等同效果未妹。
事件代理
由于事件會(huì)在冒泡階段向上傳播到父節(jié)點(diǎn)簿废,因此可以把子節(jié)點(diǎn)的監(jiān)聽函數(shù)統(tǒng)一處理多個(gè)子元素的事件空入。這種方法叫做事件的代理
定義:事件代理就是利用事件冒泡,只指定一個(gè)事件處理程序族檬,就可以管理某一類型的所有事件歪赢。(delegation)。
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event){
if(event.target.tagName.toLowerCase() === 'li'){
//...
}
})
上面代碼的click
事件的監(jiān)聽函數(shù)定義在<ul>
節(jié)點(diǎn)单料,但是實(shí)際上埋凯,它處理額是子節(jié)點(diǎn)<li>
的click
事件。這樣的好處是扫尖,只要定義一個(gè)監(jiān)聽函數(shù)白对,就能處理多個(gè)子節(jié)點(diǎn)的事件,且以后再添加子節(jié)點(diǎn)换怖,監(jiān)聽函數(shù)依然有效甩恼。
寫一個(gè) Demo,演示事件傳播的過程沉颂,演示阻止傳播的效果
- 事件傳播
//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>
//為了減少代碼量条摸,寫一個(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ù)覽