使用原生 JS 實(shí)現(xiàn)事件委托舉例

DOM事件

在我們的日常的生活中姨蝴,無(wú)時(shí)無(wú)刻不在發(fā)生著各種類型的事件俊啼。比如說(shuō)體育賽事、娛樂(lè)新聞左医、戰(zhàn)爭(zhēng)甚至天氣變化等等都可以被稱為事件。這些事件有三個(gè)共同的特點(diǎn):監(jiān)聽同木、變化浮梢、通知
轉(zhuǎn)到代碼上彤路,當(dāng)用戶使用一個(gè)程序時(shí)秕硝,代碼會(huì)監(jiān)聽用戶的行為,而用戶行為發(fā)生變化時(shí)洲尊,代碼會(huì)得到通知远豺,繼而做出反應(yīng),這就是發(fā)生在代碼上的事件坞嘀。而DOM事件就是在DOM節(jié)點(diǎn)上發(fā)生的事件躯护,通常我們會(huì)為DOM元素注冊(cè)事件處理函數(shù),來(lái)監(jiān)聽DOM事件丽涩。
DOM事件可以分為以下兩類:

  1. level 0事件
button.onclick = function(e){alert('Hello world!')}// or:
<button onclick="alert('Hello world!')">

level 0事件是在W3C認(rèn)證前的事件棺滞,可以通過(guò)如上兩種方式進(jìn)行監(jiān)聽裁蚁。這種事件的特點(diǎn)是:每個(gè)元素和事件只能設(shè)置一個(gè)事件處理函數(shù),先設(shè)置的會(huì)被后設(shè)置的覆蓋继准。

  1. level 2事件
button.addEventListener('click', function(e){alert('Hello world')});

level 2事件是經(jīng)過(guò)W3C認(rèn)證的事件枉证,它將事件的傳播方式分為了三個(gè)階段:捕獲階段(Capturing Phase)、目標(biāo)階段(Target Phase)和冒泡階段(Bubble Phase)移必。
下圖是W3C對(duì)DOM事件派發(fā)過(guò)程的圖解室谚。


DOM事件流在DOM樹中派發(fā)事件

level 2事件通過(guò)EventTarget.addEventListener() 方法將指定的監(jiān)聽器注冊(cè)到EventTarget上,當(dāng)該對(duì)象觸發(fā)指定的事件時(shí)崔泵,指定的回調(diào)函數(shù)就會(huì)被執(zhí)行舞萄。該方法允許給一個(gè)事件注冊(cè)多個(gè) listener。

事件委托

在了解什么是DOM事件以及給DOM事件綁定監(jiān)聽器的幾種方法后管削,我們來(lái)談?wù)勈录小?/p>

  1. e.targete.currentTarget
    當(dāng)我們給目標(biāo)元素target綁定一個(gè)事件監(jiān)聽器target.addEventListener(event, function(e){})倒脓,并指定回調(diào)函數(shù)function(e),函數(shù)的參數(shù)e表示事件含思。此時(shí)崎弃,e.target與e.currentTarget分別表示直接觸發(fā)事件的元素與被監(jiān)聽的元素。
    舉個(gè)栗子:
<html>
<body>
<ul style='list-style:none;max-width:200px;border:1px solid;'>
  <li>點(diǎn)我試試</li>
<ul>
<script>
  (document.querySelector('ul')).addEventListener('click' ,function(e){
    console.log('e.target')
    console.log(e.target)
    console.log('e.currentTarget')
    console.log(e.currentTarget)
  })
  </script>
</body>
</html>

這段代碼為一個(gè)ul元素綁定了一個(gè)監(jiān)聽器含潘,當(dāng)ul上發(fā)生點(diǎn)擊事件時(shí)饲做,分別輸出e.target和e.currentTarget的值。
當(dāng)點(diǎn)擊ul中的li元素時(shí)遏弱,該段代碼的在控制臺(tái)輸出的結(jié)果如下:


此時(shí)盆均,e.target為直接點(diǎn)擊的元素li,而e.currentTarget為被監(jiān)聽的元素ul漱逸。由此我們可以得到一個(gè)啟發(fā)泪姨,觸發(fā)事件的元素與被監(jiān)聽的元素不一定是一個(gè)元素。于是就來(lái)到了本文的重點(diǎn)內(nèi)容——事件委托饰抒。

  1. 如何進(jìn)行事件委托
    什么情況下會(huì)用到事件委托呢肮砾?舉兩個(gè)例子。
    (1) 當(dāng)存在多個(gè)元素可以共用同一個(gè)監(jiān)聽器袋坑。
<html>
<body>
<ul>
  <li>點(diǎn)<span>這里</span></li>
  <li>點(diǎn)這里</li>
</ul>
<style>
  ul, li{
  list-style:none;
  border:1px solid;
  padding:10px;
  background:#ddd
}
li{
  text-align:center;
  margin:10px;
  background:#fff
}
</style>
</body>
</html>

上面的代碼中定義了如圖所示的一個(gè)ul仗处,它包裹著兩個(gè)li,第一個(gè)li中還有一個(gè)子元素span枣宫。如果我們希望點(diǎn)擊兩個(gè)li均執(zhí)行同一條命令時(shí)婆誓,第一種方法是為每個(gè)li都綁定一個(gè)監(jiān)聽器,但當(dāng)li很多時(shí)也颤,這樣處理就過(guò)于繁瑣洋幻。
這時(shí)我們會(huì)想到可以直接監(jiān)聽ul,為ul綁定事件函數(shù)歇拆,那么只要li存在于ul的內(nèi)部鞋屈,點(diǎn)擊任意的一個(gè)li都會(huì)執(zhí)行這條命令范咨。但同樣存在一個(gè)問(wèn)題,當(dāng)點(diǎn)擊li的外部,也就是圖中的灰色區(qū)域時(shí),命令同樣會(huì)被執(zhí)行迹鹅。
那么如何僅僅在點(diǎn)擊li的覆蓋區(qū)域的時(shí)候才執(zhí)行這段命令呢,可以用以下這段代碼替蛉。

var ul=document.querySelector('ul')
ul.addEventListener('click',function(e){
  var el = e.target
//判斷當(dāng)前點(diǎn)擊的元素是否為li,如果不是拄氯,執(zhí)行以下的while循環(huán)
  while(el.tagName !== 'LI'){
//如果點(diǎn)擊的元素為ul躲查,直接跳出循環(huán)
    if(el === ul){
      el = null
      break;
    }
//否則,將當(dāng)前元素父元素賦給el
      el=el.parentNode
  }
//如果最后el不為null译柏,則打出'ok'
  if(el){
    console.log('ok')
  }
//否則镣煮,打出'你點(diǎn)擊的不是li'
  else console.log('你點(diǎn)擊的不是li')
})

這段代碼實(shí)現(xiàn)了當(dāng)點(diǎn)擊的區(qū)域在li范圍內(nèi)時(shí),不管點(diǎn)擊的是li元素本身鄙麦,還是li的子元素span典唇,都會(huì)執(zhí)行console.log('ok'),但當(dāng)點(diǎn)擊區(qū)域超出li的范圍胯府,則執(zhí)行' console.log('你點(diǎn)擊的不是li')'介衔。這就成功實(shí)現(xiàn)了一個(gè)事件委托。
(2) 用事件委托實(shí)現(xiàn)動(dòng)態(tài)監(jiān)控
還有一種情況骂因,也會(huì)用到事件委托炎咖,那就是需要?jiǎng)討B(tài)監(jiān)控的時(shí)候。
看以下代碼:

<html>
<body>
<ul>
  <li>1</li>
  <li>2</li>
  <li>3</li>
  <li>4</li>
</ul>
  <button id=addButton>+</button>
</body>
</html>
<style>
li{
  border: 1px solid;
}
</style>
<script>
addButton.onclick = function(){
  var li = document.createElement('li')
  li.textContent = 'new' 
  document.querySelector('ul').appendChild(li)
}
document.querySelector('ul').onclick = function(e){
  console.log(e.target)
}
</script>
</body>
</html>

這段代碼實(shí)現(xiàn)的效果如下:

當(dāng)點(diǎn)擊左下角的加號(hào)按鈕時(shí)寒波,會(huì)增加一個(gè)新的li乘盼,同時(shí)在點(diǎn)擊li時(shí),在控制臺(tái)輸出被點(diǎn)擊的li的內(nèi)容影所。這就是用事件委托實(shí)現(xiàn)動(dòng)態(tài)監(jiān)控蹦肴。

小結(jié)

本文介紹了兩種用原生JS實(shí)現(xiàn)事件委托的方法,在不同的情境與需求下猴娩,這些方法可以做不同程度的優(yōu)化,需要結(jié)合實(shí)例展開分析勺阐。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末卷中,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子渊抽,更是在濱河造成了極大的恐慌蟆豫,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件懒闷,死亡現(xiàn)場(chǎng)離奇詭異十减,居然都是意外死亡栈幸,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門帮辟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)速址,“玉大人,你說(shuō)我怎么就攤上這事由驹∩置” “怎么了?”我有些...
    開封第一講書人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵蔓榄,是天一觀的道長(zhǎng)并炮。 經(jīng)常有香客問(wèn)我,道長(zhǎng)甥郑,這世上最難降的妖魔是什么逃魄? 我笑而不...
    開封第一講書人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮澜搅,結(jié)果婚禮上伍俘,老公的妹妹穿的比我還像新娘。我一直安慰自己店展,他們只是感情好养篓,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赂蕴,像睡著了一般柳弄。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上概说,一...
    開封第一講書人閱讀 49,166評(píng)論 1 284
  • 那天碧注,我揣著相機(jī)與錄音,去河邊找鬼糖赔。 笑死萍丐,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的放典。 我是一名探鬼主播逝变,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼奋构!你這毒婦竟也來(lái)了壳影?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤弥臼,失蹤者是張志新(化名)和其女友劉穎宴咧,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體径缅,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡掺栅,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年烙肺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片氧卧。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡桃笙,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出假抄,到底是詐尸還是另有隱情怎栽,我是刑警寧澤,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布宿饱,位于F島的核電站熏瞄,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏谬以。R本人自食惡果不足惜强饮,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望为黎。 院中可真熱鬧邮丰,春花似錦、人聲如沸铭乾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)炕檩。三九已至斗蒋,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間笛质,已是汗流浹背泉沾。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妇押,地道東北人跷究。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像敲霍,于是被迫代替她去往敵國(guó)和親俊马。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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