因為兼容ie琢融,一般使用事件冒泡
事件
js和瀏覽器交互通過事件實現(xiàn)
事件流
頁面元素接受事件的順序
事件捕獲
從根節(jié)點到目標節(jié)點
目標階段
到達目標階段
事件冒泡
從當前節(jié)點上溯到根節(jié)點
js的五種監(jiān)聽方式
1.HTML事件處理程序(冒泡)
事件處理程序中的代碼在執(zhí)行時,有權訪問到全局作用域中的任何代碼簿寂。
缺點:
*違反了html與js相分離原則
*元素一出現(xiàn)就出發(fā)了事件漾抬,js還沒加載,會報錯
<body onload="doSomething()">//不是doSomething常遂,雙引號里面是js的執(zhí)行
<div onclick="console.log('觸發(fā)事件')">//單引號不能改成雙引號纳令,因為里面是js,不能使用未經轉義的html
等同于:
el.setAttribute('onclick', 'doSomething()');
2.元素節(jié)點的事件屬性(冒泡)(DOM0級事件處理)
如果這個函數中存在this關鍵字克胳,那么this就會指向這個對象
缺點:1.一個事件只能定義一個監(jiān)聽函數平绩,意思是:如果定義兩次onclick屬性,后一次覆蓋前面一次
2.我們不能控制元素的事件流(捕獲or冒泡)毯欣。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
</head>
<body>
<input id="myButton" type="button" value="click me">
<script>
var button = document.getElementById('myButton');
function handler() {
alert('click');
}
button.onclick = handler;
// 移除事件
// button.onclick = null;
</script>
</body>
</html>
3.EventTarget.addEventListener(推薦)(DOM2級事件處理程序)
this同樣指向當前元素馒过,故函數在元素的作用域中執(zhí)行。
DOM2級事件”規(guī)定的事件流包括三個階段:事件捕獲階段酗钞、處于目標階段和事件冒泡階段腹忽。
此處詳細:https://wangdoc.com/javascript/events/eventtarget.html
“DOM2級事件”規(guī)定的事件流包括三個階段:事件捕獲階段、處于目標階段和事件冒泡階段砚作。
在DOM事件流中窘奏,實際的目標在捕獲階段不會接收事件。就是說在捕獲階段葫录,事件從document到html再到body后就停止了着裹。下一個階段是“處于目標”階段,于是事件在div中發(fā)生米同,并在事件處理中被看成是冒泡階段的一部分骇扇。然后,冒泡階段發(fā)生面粮。IE8及更早的版本不支持DOM事件流少孝,瀏覽器在捕獲階段觸發(fā)事件對象上的事件,結果就是有兩個機會在目標對象上面操作事件熬苍。
(1)*DOM2級事件定義了兩個方法:addEventListener()和removeEventListener()稍走。
*需要注意的是,通過addEventListener()指定的事件處理程序只能通過removeEventListener()移除柴底;
*同時婿脸,如果在addEventListener()中的第二個參數是一個匿名函數,則無法通過removeEventListener()移除柄驻,也沒有辦法移除狐树。
*而IE實現(xiàn)了與DOM中類似的兩個方法:attachEvent()和detachEvent(),這兩個方法直接收兩個參數鸿脓,第一個為事件名稱(注意事件名稱都有on前綴褪迟,例如click事件則為onclick)冗恨,第二個參數為事件處理程序函數。
function hello() {
console.log('Hello world');
}
var button = document.getElementById('btn');
button.addEventListener('click', hello, false);//第三個參數false的時候是冒泡排序味赃,true的時候是捕獲
移除事件監(jiān)聽addEventListener:
div.addEventListener('click', listener, false);
div.removeEventListener('click', listener, false);//與addEventListener參數完全相同掀抹,并且第二個參數不能是匿名函數(會認為兩個匿名函數不是同一個)。
優(yōu)點:
*同一個事件可以添加多個監(jiān)聽函數心俗。
*能夠指定在哪個階段(捕獲階段還是冒泡階段)觸發(fā)監(jiān)聽函數傲武。
*除了 DOM 節(jié)點,其他對象(比如window城榛、XMLHttpRequest等)也有這個接口揪利,它等于是整個 JavaScript 統(tǒng)一的監(jiān)聽函數接口。
4.IE事件處理程序
IE事件處理程序中有類似與DOM2級事件處理程序的兩個方法:
*attachEvent()
*detachEvent()
$btn.attachEvent('onclick', function() {
alert('i am isaac');
});
它們都接收兩個參數:
i.事件處理程序名稱狠持。如onclick疟位、onmouseover,注意:這里不是事件喘垂,而是事件處理程序的名稱甜刻,所以有on。
ii.事件處理程序函數正勒。如function(){alert("clicked");}
(之所以沒有和DOM2級事件處理程序中類似的第三個參數得院,是因為IE8及更早版本只支持冒泡事件流。)
注意:
1.IE事件處理程序中attachEvent()的事件處理程序的作用域和DOM0與DOM2不同章贞,她的作
用域是在全局作用域中祥绞。因此,不同于DOM0和DOM2中this指向元素鸭限,IE中的this指向
window蜕径。
2.同樣,我們可以使用attachEvent()來給同一個元素添加多個事件處理程序败京。但是與DOM2
不同丧荐,事件觸發(fā)的順序不是添加的順序而是添加順序的相反順序。
3.同樣地喧枷,通過attachEvent()添加的事件處理程序必須通過detachEvent()方法移除,同樣
的弓坞,不能使用匿名函數隧甚。
4.支持IE事件處理程序的瀏覽器不只有IE瀏覽器,還有Opera瀏覽器渡冻。
5.跨瀏覽器事件處理程序
即先判斷DOM2級事件處理程序戚扳,再判斷IE事件處理程序,最后使用DOM0級事件處理程序族吻。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跨瀏覽器事件處理程序</title>
</head>
<body>
<button id="button">點我</button>
<script>
var EventUtil={
addHandler:function(element,type,handler){
if(element.addEventListener){
element.addEventListener(type,handler,false);//注意:這里默認使用了false(冒泡)
}else if(element.attachEvent){
element.attachEvent("on"+type,handler);
}else{
element["on"+type]=handler;
}
},
removeHandler:function(element,type,handler){
if(element.removeEventListener){
element.removeEventListener(type,handler,false);//注意:這里默認使用了false(冒泡)
}else if(element.detachEvent){
element.detachEvent("on"+type,handler);
}else{
element["on"+type]=null;
}
}
};
function handler(){
alert("clicked");
}
var button=document.getElementById("button");
EventUtil.addHandler(button,"click",handler);
</script>
</body>
</html>
DOM0和DOM2區(qū)別
如果定義了兩個dom0級事件帽借,dom0級事件會覆蓋
dom2不會覆蓋珠增,會依次執(zhí)行
dom0和dom2可以共存,不互相覆蓋砍艾,但是dom0之間依然會覆蓋
事件委托
<ul id="color-list">
<li>item1</li>
<li>item2</li>
<li>item3</li>
<li>item4</li>
<li>item5</li>
</ul>
<script>
(function () {
var colorList = document.getElementById("color-list");
colorList.addEventListener('click', showColor, false);
function showColor(e) {
e = e || window.event;
var target = e.target || e.srcElement;
console.log(target.innerHTML)
}
})();
</script>
好處:
(1)將多個事件處理器減少到一個蒂教,因為事件處理器要駐留內存,這樣就提高了性能脆荷。
想象如果有一個100行的表格凝垛,對比傳統(tǒng)的為每個單元格綁定事件處理器的方式和事件代理(即table上添加一個事件處理器),不難得出結論蜓谋,事件代理確實避免了一些潛在的風險梦皮,提高了性能。
桃焕、
(2)如果新增其他子元素(a,span,div等)剑肯,直接修改事件代理的事件處理函數即可,不需要重新綁定處理器观堂,不需要再次循環(huán)遍歷让网。
比如增加一個元素,事件并沒有起效:
<script>
(function () {
var colorList = document.getElementById("color-list");
var colors = colorList.getElementsByTagName("li");
for (var i = 0; i < colors.length; i++) {
colors[i].addEventListener('click', showColor, false);
}
;
function showColor(e) {
e = e || window.event;
var targetElement = e.target || e.srcElement;
console.log(targetElement.innerHTML);
}
var li=document.createElement('li');
li.innerText='123';
colorList.append(li);
})();
</script>
參照:
https://wangdoc.com/javascript/events/model.html
https://www.cnblogs.com/zhuzhenwei918/p/6139281.html#1
高級程序設計283頁開始