什么是事件?
? 事件是文檔和瀏覽器窗口中發(fā)生的特定的交互瞬間。
什么是事件流:
? ?事件流描述的是從頁(yè)面中接受事件的順序( 說(shuō)白了就是解決頁(yè)面中事件流發(fā)生順序的問(wèn)題。),但有意思的是,微軟(IE)和網(wǎng)景(Netscape)開發(fā)團(tuán)隊(duì)居然提出了兩個(gè)截然相反的事件流概念,IE的事件流是事件冒泡流(event bubbling),而Netscape的事件流是事件捕獲流(event capturing)。
?
讓我們先聊聊DOM0級(jí)事件與DOM2級(jí)事件
?
直接通過(guò) onclick寫在html里面的事件, 比如:
在標(biāo)簽內(nèi)寫onclick事件
<input onclick="alert(1)" />
?在JS寫onlicke=function(){}函數(shù)
1 document.getElementById("myButton").onclick = function () {2 alert('thanks');3 }
?
?
主流瀏覽器DOM2級(jí)事件是通過(guò)以下兩個(gè)方法用于處理指定和刪除事件處理程序的操作:
它們都有三個(gè)參數(shù):
使用DOM 2級(jí)事件處理程序的主要好處是可以添加多個(gè)事件處理程序,事件處理會(huì)按照他們的順序觸發(fā),通過(guò)addEventListener添加的事件只能用removeEventListener來(lái)移除,移除時(shí)傳入的參數(shù)與添加時(shí)使用的參數(shù)必須相同,這也意味著添加的匿名函數(shù)將無(wú)法移除,(注意:我們默認(rèn)的第三個(gè)參數(shù)都是默認(rèn)false,是指在冒泡階段添加,大多數(shù)情況下,都是將事件處理程序添加到事件的冒泡階段,這樣可以最大限度的兼容各個(gè)瀏覽器)
?
匿名函數(shù)
1 //這是一個(gè)DOM 2級(jí)事件 添加事件最簡(jiǎn)單的方式(此時(shí)添加的是一個(gè)匿名函數(shù))2 <button>按鈕</button>3 <script>4 var btn=document.querySelector('button');5 btn.addEventListener('click',function(){6 console.log('我是按鈕')7 },false) //當(dāng)?shù)谌齻€(gè)參數(shù)不寫時(shí),也是默認(rèn)為false(冒泡時(shí)添加事件)8 </script>
?
命名函數(shù)
1 <button>按鈕</button>2 <script>3 var btn=document.querySelector('button');4 btn.addEventListener('click',foo,false);5 function foo(){6 console.log('我是按鈕')7 }8 //其實(shí)操作就是把寫在里面的函數(shù)拿到了外面,而在原來(lái)的位置用函數(shù)名來(lái)代替9 </script>
?
?
看完以上的,我們?cè)倭私馐录芭菖c捕獲
?
?
第一種(事件冒泡)IE提出
IE提出的事件流叫做事件冒泡,即事件開始時(shí)由最具體的元素接收,然后逐級(jí)向上傳播到較為不具體的節(jié)點(diǎn)。
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body onclick="bodyClick()"> 8 9 <div onclick="divClick()">10 <button onclick="btn()">11 <p onclick="p()">點(diǎn)擊冒泡</p>12 </button>13 </div>14 <script>15 16 function p(){17 console.log('p標(biāo)簽被點(diǎn)擊')18 }19 function btn(){20 console.log("button被點(diǎn)擊")21 }22 function divClick(event){23 console.log('div被點(diǎn)擊');24 }25 function bodyClick(){26 console.log('body被點(diǎn)擊')27 }28 29 </script>30 31 </body>32 </html>
接下來(lái)我們點(diǎn)擊一下頁(yè)面上的p元素,如下所示
正如上面我們所說(shuō)的,它會(huì)從一個(gè)最具體的的元素接收,然后逐級(jí)向上傳播, p=>button=>div=>body..........事件冒泡可以形象地比喻為把一顆石頭投入水中,泡泡會(huì)一直從水底冒出水面。
??
??
第二種(事件捕獲)網(wǎng)景提出
事件捕獲流的思想是不太具體的DOM節(jié)點(diǎn)應(yīng)該更早接收到事件,而最具體的節(jié)點(diǎn)應(yīng)該最后接收到事件,針對(duì)上面同樣的例子,點(diǎn)擊按鈕,那么此時(shí)click事件會(huì)按照這樣傳播:(下面我們就借用addEventListener的第三個(gè)參數(shù)來(lái)模擬事件捕獲流)
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>Title</title> 6 </head> 7 <body> 8 9 <div>10 <button>11 <p>點(diǎn)擊捕獲</p>12 </button>13 </div>14 <script>15 var oP=document.querySelector('p');16 var oB=document.querySelector('button');17 var oD=document.querySelector('div');18 var oBody=document.querySelector('body');19 20 oP.addEventListener('click',function(){21 console.log('p標(biāo)簽被點(diǎn)擊')22 },true);23 24 oB.addEventListener('click',function(){25 console.log("button被點(diǎn)擊")26 },true);27 28 oD.addEventListener('click', function(){29 console.log('div被點(diǎn)擊')30 },true);31 32 oBody.addEventListener('click',function(){33 console.log('body被點(diǎn)擊')34 },true);35 36 </script>37 </body>38 </html>
同樣我們看一下后臺(tái)的打印結(jié)果
和冒泡流完全相反,從最不具體的元素接收到最具體的元素接收事件? body=>div=>button=>p?
?
?
在實(shí)際的開發(fā)當(dāng)中,利用事件流的特性,我們可以使用一種叫做事件代理的方法。
<ul id="color-list"> <li>red</li> <li>yellow</li> <li>blue</li> <li>green</li> <li>black</li> <li>white</li></ul>
?
?如果點(diǎn)擊頁(yè)面中的li元素,然后輸出li當(dāng)中的顏色,我們通常會(huì)這樣寫:
1 var list_li = document.getElementsByTagName('li');2 for (var i = 0; i < list_li.length; i ) {3 list_li[i].addEventListener('click',foo,false);4 }5 function foo (e) {6 let x = e.target;7 console.log(x.innerHTML)8 }
?
利用事件流的特性,我們只綁定一個(gè)事件處理函數(shù)也可以完成:
1 var list_ul = document.getElementById('color-list');2 list_ul.addEventListener('click', foo, false);3 function foo (e) {4 let x = e.target;5 if (x.nodeName == 'LI') {6 console.log(x.innerHTML)7 }8 }
?
?
?
對(duì)于事件代理來(lái)說(shuō),在事件捕獲或者事件冒泡階段處理并沒有明顯的優(yōu)劣之分,但是由于事件冒泡的事件流模型被所有主流的瀏覽器兼容,從兼容性角度來(lái)說(shuō)還是建議大家使用事件冒泡模型。
?
IE瀏覽器對(duì)addEventListener兼容性并不算太好,只有IE9以上可以使用。
要兼容舊版本的IE瀏覽器,可以使用IE的attachEvent函數(shù)
object.attachEvent(event, function)
兩個(gè)參數(shù)與addEventListener相似,分別是事件和處理函數(shù),默認(rèn)是事件冒泡階段調(diào)用處理函數(shù)。并且由于IE瀏覽器只支持事件冒泡,所以添加的程序都被添加到冒泡階段。要注意的是,寫事件名時(shí)候要加上"on"前綴("onload"、"onclick"等)。
?
addEventListener與attachEvent除了參數(shù)個(gè)數(shù)以及第一個(gè)參數(shù)意義不同外。還有如下兩點(diǎn):
?
?
阻止事件冒泡 ??stopPropagation() 方法
可以阻止事件冒泡,也可以阻止事件捕獲,也可以阻止處于目標(biāo)階段
使用stopPaopagation()方法可以停止事件在DOM層次的傳播,不再派發(fā)事件。
1 <div id="p">parent 2 <div id="c">child</div> 3 </div> 4 <script type="text/javascript"> 5 var p = document.getElementById('p'), 6 c = document.getElementById('c'); 7 c.addEventListener('click', function (e) { 8 e.stopPropagation() 9 alert('子節(jié)點(diǎn)冒泡') //不再向上冒泡到父級(jí)10 }, false);11 p.addEventListener('click', function () {12 alert('父節(jié)點(diǎn)冒泡')}, false);13 </script>
?
阻止默認(rèn)事件 ??event.preventDefault() 方法 ? (基本沒作用吧...很少有需求將默認(rèn)事件取消掉吧)
event.preventDefault()
?
?
來(lái)源:http://www.icode9.com/content-4-156851.html聯(lián)系客服