深入JS事件冒泡與事件代理(委托)

事件作為DOM操作中重要的一個(gè)點(diǎn),好好的理解并運(yùn)用相當(dāng)?shù)闹匾?/p>

1呻顽、事件冒泡

簡(jiǎn)單的說(shuō)雹顺,就是當(dāng)一個(gè)子元素的事件被觸發(fā)的時(shí)候(如onclick事件),該事件會(huì)從事件源(被點(diǎn)擊的子元素)開(kāi)始逐級(jí)向上傳播廊遍,觸發(fā)父級(jí)元素的點(diǎn)擊事件嬉愧。

 <div id="parent" style="background-color: #000;height: 400px;width: 400px" data-id="11">  
    <div id="child" style="background-color: #fff;height: 200px;width: 200px" data-id="22"></div>  
 </div> 

document.getElementById('parent').onclick=function () {  
    console.log(this.getAttribute('data-id'));  
};  
document.getElementById('child').onclick=function (e) {  
    console.log(this.getAttribute('data-id'));  
};  

在線運(yùn)行: http://jsbin.com/ritivosoco/edit?html,js,console,output

這里我們可以發(fā)現(xiàn),當(dāng)你點(diǎn)擊白色區(qū)域(子元素)昧碉,父級(jí)的click事件也被觸發(fā)啦(觀察控制臺(tái)的輸出)英染,那么這里就有一個(gè)問(wèn)題啦揽惹,可不可以當(dāng)點(diǎn)擊子元素的時(shí)候不觸發(fā)父元素的點(diǎn)擊事件啊被饿,這就是接下來(lái)要說(shuō)的啦

2、阻止事件冒泡

所謂阻止事件冒泡其實(shí)啊搪搏,就是我們不讓點(diǎn)擊這個(gè)事件傳遞給父元素啊狭握,哈哈,這就要用到事件中的一個(gè)stopPropagation()方法啦,還是先看代碼吧

document.getElementById('parent').onclick=function () {  
    console.log(this.getAttribute('data-id'));  
};  
document.getElementById('child').onclick=function (e) {  
    console.log(this.getAttribute('data-id'));  
    e.stopPropagation();  
};  

在線運(yùn)行: http://jsbin.com/ritivosoco/edit?html,js,console,output

嘿嘿疯溺,此刻你在線上運(yùn)行的時(shí)候是不是發(fā)現(xiàn)當(dāng)我們點(diǎn)擊白色區(qū)域的時(shí)候并沒(méi)有觸發(fā)到父元素的點(diǎn)擊事件啊论颅,這是因?yàn)槲覀冏柚沽俗釉氐氖录芭堇玻?/p>

朋友們有可能會(huì)覺(jué)得事件冒泡真是煩人,寫(xiě)個(gè)事件還要阻止冒泡囱嫩!不過(guò)凡事都有雙刃劍恃疯,事件冒泡同時(shí)給我們帶來(lái)的還有事件委托這一減少DOM操作的神器,接下來(lái)介紹哦

3墨闲、事件委托

事件委托今妄,首先按字面的意思就能看你出來(lái),是將事件交由別人來(lái)執(zhí)行,再聯(lián)想到上面講的事件冒泡盾鳞,是不是想到了犬性?對(duì)啦,其實(shí)就是將子元素的事件通過(guò)冒泡的形式交由父元素來(lái)執(zhí)行腾仅。

可能在開(kāi)發(fā)的時(shí)候會(huì)遇到這種情況:如導(dǎo)航每一個(gè)欄目都要加一個(gè)事件乒裆,你可能會(huì)通過(guò)遍歷來(lái)給每個(gè)欄目添加事件,首先我們來(lái)看一段不使用事件委托的代碼, 我們遍歷子元素?cái)?shù)組:

 <ul id="parent">  
   <li>孩子1</li>  
   <li>孩子2</li>  
   <li>孩子3</li>  
   <li>孩子4</li>  
   <li>孩子5</li>
 </ul>
 var ul = document.getElementById('parent')
 var lis = ul.getElementsByTagName('li')
 for (var i = 0; i<lis.length;i++){  
   lis[i].onclick= function() {  
     alert(this.innerHTML);  
   }
 }

這種方式看起來(lái)直接明了推励,但需要多次操作dom(每點(diǎn)擊一個(gè)li都會(huì)操作一次dom)鹤耍,如果子元素較多的話則是一件相當(dāng)恐怖的事情,而且當(dāng)我們后面添加一個(gè)新的li子元素后验辞,新添加的li沒(méi)有綁定事件惰蜜,需要再次給新的li綁定一次,考慮到給新添加的元素綁定事件:

<ul id="parent">  
   <li>孩子1</li>  
   <li>孩子2</li>  
   <li>孩子3</li>  
   <li>孩子4</li>  
   <li>孩子5</li>
 </ul>
 var ul = document.getElementById('parent')
 var lis = ul.getElementsByTagName('li')
 function addClick() {
   for (var i = 0; i<lis.length;i++){  
     lis[i].onclick= function() {  
       alert(this.innerHTML);  
     }
   }
}
addClick()

function addElement() {  
   var li = document.createElement('li');  
   li.innerHTML="我是新孩子";  
   ul.appendChild(li);  
   addClick();  
} 
addElement();  

上面寫(xiě)的代碼確實(shí)可以解決新添加子元素的問(wèn)題受神,但代碼就有點(diǎn)多了抛猖,而且本質(zhì)上并沒(méi)有改變DOM的操作次數(shù),優(yōu)化性能鼻听,下面我們直接來(lái)看事件委托的寫(xiě)法:

<ul id="parent">
  <li>孩子1</li>  
  <li>孩子2</li>  
  <li>孩子3</li>  
  <li>孩子4</li>  
  <li>孩子5</li>
</ul>

var ul = document.getElementById('parent');  
ul.onclick = function (e) {  
  //判斷只有l(wèi)i觸發(fā)的才會(huì)輸出內(nèi)容  
  if(e.target.nodeName.toLowerCase() === "li"){
    alert(e.target.innerHTML);  
  }  
  e.stopPropagation();                          
}

在線運(yùn)行: http://jsbin.com/bamonabeda/16/edit?html,js,console,output

因?yàn)槭潜O(jiān)聽(tīng)的父元素财著,所有即使新添加元素也是可以默認(rèn)綁定好事件的,這樣我們可以看到代碼更簡(jiǎn)潔了撑碴,也減少了dom的操作次數(shù)撑教,是不是非常的優(yōu)雅和nice啊醉拓!

4伟姐、總結(jié)

最后總結(jié)下哈,事件冒泡是個(gè)雙刃劍亿卤,當(dāng)對(duì)我們有負(fù)面的影響的時(shí)候就顯得相當(dāng)討厭愤兵,不過(guò)我們可以用阻止冒泡來(lái)達(dá)到我們想要的效果;但是在另一方面在特定的場(chǎng)合我們又可以借助于事件冒泡來(lái)優(yōu)化我們的代碼排吴,優(yōu)化性能秆乳,只有對(duì)原理了解于心,才可以突破更多的限制钻哩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末屹堰,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子街氢,更是在濱河造成了極大的恐慌扯键,老刑警劉巖,帶你破解...
    沈念sama閱讀 210,835評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件珊肃,死亡現(xiàn)場(chǎng)離奇詭異荣刑,居然都是意外死亡扣泊,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,900評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)嘶摊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)延蟹,“玉大人,你說(shuō)我怎么就攤上這事叶堆≮迤” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,481評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵虱颗,是天一觀的道長(zhǎng)沥匈。 經(jīng)常有香客問(wèn)我,道長(zhǎng)忘渔,這世上最難降的妖魔是什么高帖? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,303評(píng)論 1 282
  • 正文 為了忘掉前任,我火速辦了婚禮畦粮,結(jié)果婚禮上散址,老公的妹妹穿的比我還像新娘。我一直安慰自己宣赔,他們只是感情好预麸,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,375評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著儒将,像睡著了一般吏祸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上钩蚊,一...
    開(kāi)封第一講書(shū)人閱讀 49,729評(píng)論 1 289
  • 那天贡翘,我揣著相機(jī)與錄音,去河邊找鬼砰逻。 笑死鸣驱,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诱渤。 我是一名探鬼主播丐巫,決...
    沈念sama閱讀 38,877評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勺美!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起碑韵,我...
    開(kāi)封第一講書(shū)人閱讀 37,633評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤赡茸,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后祝闻,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體占卧,經(jīng)...
    沈念sama閱讀 44,088評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遗菠,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,443評(píng)論 2 326
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了华蜒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片辙纬。...
    茶點(diǎn)故事閱讀 38,563評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖叭喜,靈堂內(nèi)的尸體忽然破棺而出贺拣,到底是詐尸還是另有隱情,我是刑警寧澤捂蕴,帶...
    沈念sama閱讀 34,251評(píng)論 4 328
  • 正文 年R本政府宣布譬涡,位于F島的核電站,受9級(jí)特大地震影響啥辨,放射性物質(zhì)發(fā)生泄漏涡匀。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,827評(píng)論 3 312
  • 文/蒙蒙 一溉知、第九天 我趴在偏房一處隱蔽的房頂上張望陨瘩。 院中可真熱鬧,春花似錦级乍、人聲如沸拾酝。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,712評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)蒿囤。三九已至,卻和暖如春崇决,著一層夾襖步出監(jiān)牢的瞬間材诽,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,943評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工恒傻, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留脸侥,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,240評(píng)論 2 360
  • 正文 我出身青樓盈厘,卻偏偏與公主長(zhǎng)得像睁枕,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子沸手,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,435評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容