1羊娃、事件傳播機(jī)制
事件流描述的是從頁面中接收事件的順序,比如有一個嵌套的div埃跷,我們點(diǎn)擊了內(nèi)層div,這時這個click事件是內(nèi)層先觸發(fā)還是外層先觸發(fā)呢蕊玷,目前事件的傳播機(jī)制主要有三種:
1、冒泡事件: 事件開始時弥雹,是由目標(biāo)元素最先觸發(fā)垃帅,然后逐級像上傳播,直到根節(jié)點(diǎn)
2剪勿、捕獲事件:捕獲事件和冒泡事件相反贸诚,由根節(jié)點(diǎn)先觸發(fā)事件,然后逐級向內(nèi)傳播厕吉,直到目標(biāo)元素
3酱固、DOM事件:DOM2事件規(guī)定事件流分為三個階段:首先為捕獲階段,為截取事件提供機(jī)會头朱。然后是實(shí)際目標(biāo)接受階段运悲,最后是冒泡階段
舉個栗子:操作一下可以更直觀的理解
<style>
.container,
.box,
.target{
border: 1px solid;
padding: 10px;
}
</style>
<div class="container">
container
<div class="box">
box
<div class="target">target</div>
</div>
</div>
冒泡事件:
function $(selector){
return document.querySelector(selector)
}
$(".container").addEventListener('click', function(e){
console.log('container....冒泡階段')
},false)
$('.box').addEventListener('click',function(e){
console.log('box....冒泡階段')
},false)
$('.target').addEventListener('click',function(e){
console.log('target....冒泡階段')
},false)
— 通過例子可以看出冒泡階段是由內(nèi)部目標(biāo)元素先觸發(fā)事件,然后逐級像外傳播的项钮,直到根元素
捕獲事件:
$(".container").addEventListener('click', function(e){
console.log('container....捕獲階段')
},true)
$('.box').addEventListener('click',function(e){
console.log('box....捕獲階段')
},true)
$('.target').addEventListener('click',function(e){
console.log('target....捕獲階段')
},true)
— 捕獲階段是外部根元素先觸發(fā)事件班眯,然后像內(nèi)逐級傳播,最后到達(dá)目標(biāo)元素
2烁巫、阻止傳播
DOM2級事件定義了兩個方法用于處理指定和刪除事件處理程序的操作:
1署隘、addEventListener
2、removeEventListener
所有的DOM節(jié)點(diǎn)都包含這兩個方法亚隙,并且它們都接受三個參數(shù):
1定踱、事件類型
2、事件處理方法
3恃鞋、布爾參數(shù)崖媚,如果是true表示在捕獲階段調(diào)用事件處理程序,如果是false恤浪,則是在事件冒泡階段處理
3畅哑、取消默認(rèn)事件
冒泡和捕獲是事件的兩種行為,使用event.stopPropagation()起到阻止捕獲和冒泡階段中當(dāng)前事件的進(jìn)一步傳播水由。使用event.preventDefault()可以取消默認(rèn)事件荠呐。
阻止事件冒泡與捕獲:w3c的方法是e.stopPropagation(),IE則是使用e.cancelBubble = true。stopPropagation作為事件對象(Event)的一個方法泥张,作用是阻止目標(biāo)元素的冒泡事件呵恢,但是會不阻止默認(rèn)行為。
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的時候媚创,由于事件冒泡渗钉,body的click事件也會觸發(fā),但是調(diào)用這句后钞钙,事件會停止傳播
取消默認(rèn)事件的方法:w3c的方法是e.preventDefault()鳄橘,IE則是使用e.returnValue = false;
要阻止事件的默認(rèn)行為芒炼,可以使用preventDefault()方法瘫怜,比如我們可以阻止鏈接導(dǎo)航這一默認(rèn)行為
document.querySelector('#btn').onclick = function (e) {
e.preventDefault();
}
4、事件代理
事件代理又稱為“事件委托”本刽。意思是把原本需要綁定在子元素上的事件委托給父元素鲸湃,讓父元素負(fù)責(zé)監(jiān)聽的職務(wù),委托代理的原理是DOM元素的事件冒泡子寓。
假如有這樣一個HTML片段
<div class="container">
<div class="box">box1</div>
<div class="box">box2</div>
<div class="box">box3</div>
</div>
<button id="add">add</button>
點(diǎn)擊每個class為box的元素暗挑,都會在控制臺打印出他們的內(nèi)容。
點(diǎn)擊id為add的按鈕别瞭,可以增加一個class=box的div元素。同樣點(diǎn)擊他們可以打印出他們的內(nèi)容
我們常常會這樣寫
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
$$('.box').forEach(function(val){
val.addEventListener('click',function(){
console.log(this.innerText)
})
})
var i= 4
$('#add').onclick=function(){
var box=document.createElement('div')
box.innerText='box' + (i++)
box.classList.add('box')
$('.container').appendChild(box)
}
打印結(jié)果:
會發(fā)現(xiàn)只有box1,box2,box3可以在控制臺打印出來株憾,新建的box4蝙寨,box5卻不行。因?yàn)樽铋_始頁面上只有3個class為box的元素嗤瞎,所以js只為這三個元素綁定了click事件墙歪,后面我們add新的div需要重新添加click事件才會有效果,這就很頭疼了贝奇。這個時候我們就需要事件委托了:
function $(selector){
return document.querySelector(selector)
}
function $$(selector){
return document.querySelectorAll(selector)
}
var i= 4
$('#add').onclick=function(){
var box=document.createElement('div')
box.innerText='box' + (i++)
box.classList.add('box')
$('.container').appendChild(box)
}
$('.container').onclick=function(e){
if(e.target.classList.contains('box')){
console.log(e.target.innerText)
}
}
打印結(jié)果:
這樣就再也不用擔(dān)心新建元素內(nèi)容出不來嘍~~~