先來張圖理解一下事件冒泡,時間捕獲
冒泡:當事件在某一DOM元素被觸發時,例如用戶在客戶名字節點上點擊鼠標,事件將跟隨着該節點,繼承各自的父節點冒泡穿過整個的DOM節點層次,直到它遇到依附有該事件類型處理器的節點,此時,該事件是onclick事件。在冒泡過程中的任何時候都可以終止事件的冒泡,在遵從W3C標準的瀏覽器裏可以通過調用事件對象上的stopPropagation()方法,在Internet Explorer裏可以通過設置事件對象的cancelBubble屬性爲true。如果不停止事件的傳播,事件將一直通過DOM冒泡直至到達文檔根。默認情況下,事件使用冒泡事件流,不使用捕獲事件流
捕獲:事件的處理將從DOM層次的根開始,而不是從觸發事件的目標元素開始,事件被從目標元素的所有祖先元素依次往下傳遞。在這個過程中,事件會被從文檔根到事件目標元素之間各個繼承派生的元素所捕獲,如果事件監聽器在被註冊時設置了useCapture屬性爲true,那麼它們可以被分派給這期間的任何元素以對事件做出處理;否則,事件會被接着傳遞給派生元素路徑上的下一元素,直至目標元素。事件到達目標元素後,它會接着通過DOM節點再進行冒泡。
<style>
.block1 {
background-color: red;
width: 500px;
height: 300px;
}
.block2 {
background-color: blue;
width: 500px;
height: 200px;
}
.block3 {
background-color: green;
width: 500px;
height: 100px;
}
</style>
</head>
<body>
<div class="block1">
<div class="block2">
<div class="block3">
</div>
</div>
</div>
<script type="text/javascript">
var block = document.getElementsByTagName('div');
冒泡
block[0].addEventListener("click",function(){
alert(1);
},false);
block[1].addEventListener("click",function(){
alert(2);
},false);
block[2].addEventListener("click",function(){
alert(3);
},false);
捕獲
block[0].addEventListener("click",function(){
alert(1);
},true);
block[1].addEventListener("click",function(){
alert(2);
},true);
block[2].addEventListener("click",function(){
alert(3);
},true);
</script>
</body>
再來說一下dom事件流,(事件流指的是從頁面接收事件的順序。)
DOM事件流:將事件分爲三個階段:捕獲階段、目標階段、冒泡階段。先調用捕獲階段的處理函數,其次調用目標階段的處理函數,最後調用冒泡階段的處理函數
block[0].addEventListener("click",function(){
alert(1);
},false);
block[1].addEventListener("click",function(){
alert(2);
},false);
block[2].addEventListener("click",function(){
alert(3);
},false);
block[0].addEventListener("click",function(){
alert(1);
},true);
block[1].addEventListener("click",function(){
alert(2);
},true);
這段代碼在點擊最內層的也就是綠色的時候,會彈出1,2(捕獲),3(處於目標狀態),2,1(冒泡)。而且被點擊元素設爲冒泡或者捕獲(第三個參數爲true 或false)是不影響的。
阻止事件冒泡和捕獲
block[2].addEventListener("click",function(event){
alert(3);
event.stopPropagation();
},false);
將上面的代碼改稱這個,即在處於目標狀態時阻止後面的冒泡進行,所以只會輸出1,2,3.
事件委託:
先借用網上的例子講一下:有三個同事預計會在週一收到快遞。爲簽收快遞,有兩種辦法:一是三個人在公司門口等快遞;二是委託給前臺MM代爲簽收。現實當中,我們大都採用委託的方案(公司也不會容忍那麼多員工站在門口就爲了等快遞)。前臺MM收到快遞後,她會判斷收件人是誰,然後按照收件人的要求籤收,甚至代爲付款。這種方案還有一個優勢,那就是即使公司裏來了新員工(不管多少),前臺MM也會在收到寄給新員工的快遞後覈實並代爲簽收。
其中我們要特別注意在新員工進來後也要享受可以代收快遞。
再看看事件委託的原理:
事件委託是利用事件的冒泡原理來實現的,何爲事件冒泡呢?就是事件從最深的節點開始,然後逐步向上傳播事件,舉個例子:頁面上有這麼一個節點樹,div>ul>li>a;比如給最裏面的a加一個click點擊事件,那麼這個事件就會一層一層的往外執行,執行順序a>li>ul>div,有這樣一個機制,那麼我們給最外面的div加點擊事件,那麼裏面的ul,li,a做點擊事件的時候,都會冒泡到最外層的div上,所以都會觸發,這就是事件委託,委託它們父級代爲執行事件。
首先想一下爲什麼用事件委託
<ul id="uli">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<script type="text/javascript">
var ul = document.getElementById('uli')
var li = ul.getElementsByTagName('li');
for (var i = 0; i < li.length; i++) {
li[i].onclick = function(){
alert(123);
};
}
</script>
先看看上面的代碼,相信能看到這裏的人一定能理解上面的代碼,上面的代碼每次點擊的時候都要找一遍ul,在遍歷一次li;
這樣會增加很多的dom操作。
var ul = document.getElementById('uli')
ul.onclick = function(){
alert(124);
}
再來看看這段代碼,因爲我們在最外面加了一個點擊事件,所以在內層點擊時,會冒泡到最外層,也就是會委託父級代爲執行。
細心的同學會發現再點擊的不是li元素但是在ul內也會觸發onclick事件,但是這就與我們最初的想法有分歧了。
<script type="text/javascript">
var ul = document.getElementById('uli');
ul.onclick = function(event){
var event = event || window.event;
var target = event.target;
if(target.tagName.toLowerCase() == 'li')
{
alert(124);
}
};
</script>
這段代碼在我們點擊的時候會判斷點擊的是不是li元素。
解決了這個問題,接下來該解決新員工的問題了,肯定有人想新員工進來不應該直接有這個屬性嗎,下面給出一段代碼自己試一下
<ul id="uli">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
<button id="button">add</button>
<script type="text/javascript">
var ul = document.getElementById('uli');
var li = ul.getElementsByTagName('li');
var button = document.getElementById('button');
for(var i=0; i<li.length;i++){
li[i].onmouseover = function(){
this.style.background = 'red';
};
li[i].onmouseout = function(){
this.style.background = '#fff';
};
}
//添加新節點
button.onclick = function(){
var oLi = document.createElement('li');
oLi.innerText = '5';
ul.appendChild(oLi);
};
</script>
試過的小夥伴應該會發現新加的li是沒有移入變紅的,
再說下一般的解決方式:
function mHover () {
//鼠標移入變紅,移出變白
for(var i=0; i<li.length;i++){
li[i].onmouseover = function(){
this.style.background = 'red';
};
li[i].onmouseout = function(){
this.style.background = '#fff';
}
}
}
但是這個又添加了一個dom操作。
再看看事件委託怎麼解決:
ul.onmouseover = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "red";
}
};
ul.onmouseout = function(ev){
var ev = ev || window.event;
var target = ev.target || ev.srcElement;
if(target.nodeName.toLowerCase() == 'li'){
target.style.background = "#fff";
}
};
button.onclick = function(){
var oLi = document.createElement('li');
ul.appendChild(oLi);
};
有興趣的小夥伴可以去試試。或者還不理解或者有疑問的可以直接提問也可以去看看這篇博客http://www.cnblogs.com/liugang-vip/p/5616484.html