通俗的說是這個事件須要綁定在我身上的,綁定在別人身上,也能達到一樣的效果,也就是綁定在別人身上,我也能監聽到。javascript
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<ul id="ul-test">
<li>0</li>
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
<li>6</li>
<li>7</li>
<li>8</li>
<li>9</li>
</ul>
</body>
<script type="text/javascript">
var oUl=document.getElementById("ul-test");
var oLi=oUl.getElementsByTagName("li");
for(var i=0,len=oLi.length;i<len;i++){
oLi[i].addEventListener("click",function(){
alert(this.innerHTML)
})
}
</script>
</html>
複製代碼
問題在於:
1.for循環,循環的是li,10個li就循環10次,綁定10次事件,1000個就循環了1000次,綁定1000次事件!
2.若是li不是原本就在頁面上的,是將來元素,是頁面加載了,再經過js動態加載進來了,上面的寫法是無效的,點擊li是沒有反應的!html
應該怎麼解決以上問題?java
var oUl=document.getElementById("ul-test");
oUl.addEventListener("click",function(ev){
console.log(ev)
var ev=ev||window.event;
var target=ev.target||ev.srcElement;
//若是點擊的最底層是li元素
if(target.tagName.toLowerCase()==='li'){
alert(target.innerHTML)
}
})複製代碼
當一個事件發生之後,它會在不一樣的DOM節點之間傳播(propagation)。這種傳播分紅三個階段:瀏覽器
第一階段:從window對象傳導到目標節點,稱爲「捕獲階段」(capture phase)。bash
第二階段:在目標節點上觸發,稱爲「目標階段」(target phase)。函數
第三階段:從目標節點傳導回window對象,稱爲「冒泡階段」(bubbling phase)。ui
這種三階段的傳播模型,會使得一個事件在多個節點上觸發。好比,假設點擊<div>
之中嵌套一個<p>
節點。
this
<div>
<p>Click Me</p>
</div>複製代碼
若是對這兩個節點的click
事件都設定監聽函數,則click
事件會被觸發四次。
spa
var phases = {
1: 'capture',
2: 'target',
3: 'bubble'
};
var div = document.querySelector('div');
var p = document.querySelector('p');
div.addEventListener('click', callback, true);
p.addEventListener('click', callback, true);
div.addEventListener('click', callback, false);
p.addEventListener('click', callback, false);
function callback(event) {
var tag = event.currentTarget.tagName;
var phase = phases[event.eventPhase];
console.log("Tag: '" + tag + "'. EventPhase: '" + phase + "'");
}
// 點擊之後的結果
// Tag: 'DIV'. EventPhase: 'capture'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'P'. EventPhase: 'target'
// Tag: 'DIV'. EventPhase: 'bubble'複製代碼
<div>
向<p>
傳播時,觸發<div>
的click
事件;<div>
到達<p>
時,觸發<p>
的click
事件;<p>
時,觸發<p>
的click
事件;<p>
傳回<div>
時,再次觸發<div>
的click
事件。注意,用戶點擊網頁的時候,瀏覽器老是假定click
事件的目標節點,就是點擊位置的嵌套最深的那個節點(嵌套在<div>
節點的<p>
節點)。因此,<p>
節點的捕獲階段和冒泡階段,都會顯示爲target
階段。
代理
事件傳播的最上層對象是window
,接着依次是document
,html
(document.documentElement
)和body
(document.body
)。也就是說,若是<body>
元素中有一個<div>
元素,點擊該元素。事件的傳播順序,在捕獲階段依次爲window
、document
、html
、body
、div
,在冒泡階段依次爲div
、body
、html
、document
、window
。
因爲事件會在冒泡階段傳向父節點,所以能夠把子節點的監聽函數綁定在父節點上,用父節點的監聽函數統一處理多個子節點的事件,這就是事件代理。
var ul = document.querySelector('ul');
ul.addEventListener('click', function(event) {
if (event.target.tagName.toLowerCase() === 'li') {
// some code
}
});複製代碼
上面這個函數事件監聽綁在ul身上,可是監聽到點擊li的事件,而後處理li點擊後的回調。
就算li是動態添加進來的依然可以監聽到。
因爲一個事件在傳播的過程當中有三個階段,由最外層的父節點一層層傳遞到最裏面的子節點,先是捕獲階段,到目標階段,再到冒泡階段。若是咱們想監聽到動態添加的子節點的事件,咱們能夠把事件綁在父節點上,利用event.target,篩選到子節點,處理事件相應的回調!!!