js事件監聽:addEventListener() 與 移除事件:removeEventListener()
說事件繫結得先說事件流
事件流
冒泡型事件流:事件的傳播是從最特定的事件目標到最不特定的事件目標。即從DOM樹的葉子到根。【推薦】
捕獲型事件流:事件的傳播是從最不特定的事件目標到最特定的事件目標。即從DOM樹的根到葉子。
DOM標準採用捕獲+冒泡。兩種事件流都會觸發DOM的所有物件,從document物件開始,也在document物件結束。
來個例子看一下吧!
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> </head> <body> <div id="myDiv">Click me!</div> </body> </html>
當點選了div時事件流走向,
在冒泡型事件流中click事件傳播順序為:<div> =》<body> =》<html> =》document
在捕獲型事件流中click事件傳播順序為:document =》<html> =》<body> =》<div>
這裡之所以說冒泡,並不是檢視上的冒泡,而是結構上的冒泡。這裡要弄清楚了,就算在檢視上div是獨立的,但他的在html結構
結構上依舊是被body所包裹。而冒泡是由內而外向上冒泡。
懂了冒泡之後,捕獲就好理解了,就是反向的事件流。由外而內。
事件處理
以上明白了事件流,現在說說怎樣處理事件。
HTML事件處理:
直接在標籤內繫結事件,例如:<button onclick="something()"></button>
這裡直接將js內something函式繫結到button上。
缺點:
1.一個方法需要多次引用,而且不符合 行為、結構、樣式 相分離的原則。
2.當js的函式名更改,html標籤內的方法也需要更改。
DOM 0級事件處理:
在<script>中獲取dom元素繫結事件,例如:btn.onclick = function () {}
0級事件處理的較HTML事件處理的有點很明顯,他完全寫在<script>內,符合 行為、結構、樣式
相分離的原則。還可以選出DOM元素集合通過for迴圈統一操作。缺點:每個DOM元素只能繫結一個同類事件。例如繫結onclick,當你想在繫結onclick會發現他被覆蓋了。
DOM 2級事件處理(事件監聽)
addEventListener("事件名" , "事件處理函式" , "布林值");
false 事件冒泡 true 事件捕獲
優點相比前兩個就多了。可以選擇是事件流。可繫結多個同類事件。事件名可以組成字串。
到今天的主題了~~
addEventListener() 和 removeEventListener()
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>addEventListener</title>
<script type="text/javascript" src="js/jquery-3.0.0.js"></script>
<style type="text/css">
#content{
width: 100px;
height: 100px;
background: #f9f;
}
</style>
</head>
<body>
<div id="content"></div>
<script type="text/javascript">
//addEventListener 用於向指定元素新增事件控制代碼
//可以向一個元素新增多次點選事件,後一個點選事件不會覆蓋前一個點選事件
var content = document.getElementById("content");
content.addEventListener("click",function(){
console.log("11");
},false)
content.addEventListener("click",function(){
console.log("22");
},false)
content.addEventListener("mouseenter",add,false);
function add(){
console.log("成哥沒我帥");
}
//由於成哥並不這麼認為,一再用自身的權勢讓我更改這個事實,所以下面我需要再移出這個事件
content.removeEventListener("mouseenter",add,false);
</script>
</body>
</html>
注意:removeEventListener() 不能移除匿名函式,像上面add()這種是可以的。removeEventListener需要知道你需要移出的是哪個事件處理函式。匿名函式丟棄了自身函式名,所以移出不了。
下面再講一些補充吧。
阻止預設事件preventDefault()
document.body.addEventListener('touchmove', function (event) {
event.preventDefault();
},false);
阻止事件冒泡stopPropagation()
解釋:只點擊了button,但是包含button的div也執行了,這屬於事件冒泡,事件逐級向上傳遞,傳給了div,有時並不需要事件冒泡,可以通過stopPropagation()
<div id="div">
<button id="btn">按鈕</button>
</div>
<script>
document.getElementById("btn").addEventListener("click",showType);
document.getElementById("div").addEventListener("click",showDiv);
function showType(event){
alert(event.type);
event.stopPropagation();
}
function showDiv(){
alert("div");
}
</script>
事件代理
這裡歸類可能沒歸好,也看看吧
傳統的事件處理中,需要為每個元素新增事件處理器。js事件代理則是一種簡單有效的技巧,通過它可以把事件處理器新增到一個父級元素上,從而避免把事件處理器新增到多個子級元素上。
事件代理的原理用到的就是事件冒泡和目標元素,把事件處理器新增到父元素,等待子元素事件冒泡,並且父元素能夠通過target(IE為srcElement)判斷是哪個子元素,從而做相應處理
傳統事件處理,為每個元素新增事件處理器,程式碼如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<ul id="color-list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>indigo</li>
<li>purple</li>
</ul>
<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;
alert(targetElement.innerHTML);
}
})();
</script>
</body>
</html>
事件代理的處理方式,程式碼如下:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<ul id="color-list">
<li>red</li>
<li>orange</li>
<li>yellow</li>
<li>green</li>
<li>blue</li>
<li>indigo</li>
<li>purple</li>
</ul>
<script>
(function(){
var colorList=document.getElementById("color-list");
colorList.addEventListener('click',showColor,false);
function showColor (e) {
e=e||window.event;
var targetElement=e.target||e.srcElement;
if(targetElement.nodeName.toLowerCase()==="li"){
alert(targetElement.innerHTML);
}
}
})();
</script>
</body>
</html>
事件代理的好處
總結一下事件代理的好處:
- 將多個事件處理器減少到一個,因為事件處理器要駐留記憶體,這樣就提高了效能。想象如果有一個100行的表格,對比傳統的為每個單元格繫結事件處理器的方式和事件代理(即table上新增一個事件處理器),不難得出結論,事件代理確實避免了一些潛在的風險,提高了效能。
- DOM更新無需重新繫結事件處理器,因為事件代理對不同子元素可採用不同處理方法。如果新增其他子元素(a,span,div等),直接修改事件代理的事件處理函式即可,不需要重新繫結處理器,不需要再次迴圈遍歷。
而代理事件需要注意的是事件冒泡, 例如:Li裡有span,這時我只想操作Li那我就要用到阻止冒泡了。
好了,就到這裡吧。本次分享到這裡就結束了,作者自身的技術不是很好,如果有哪裡誤導了大家,請留言提醒我一下。
並不是很全,不過夠用了,裡面沒有提及觸屏事件等等。