今天我做了一實驗破喻,想要實現(xiàn)當一個div嵌套另外一個div的時候,點擊外層div的時候觸發(fā)事件,而點擊內層div的時候不進行事件觸發(fā),代碼如下:
原本我想著只給容器ct添加一個事件而不給其內的子元素添加事件赊抖,就能實現(xiàn)我的效果,結果后來意識到內層的div也屬于容器ct的一部分寨典,這樣做無論點擊容器部分還是內層div都會觸發(fā)效果:
然后我心想如果能把外層ct容器和內層的div分辨出來不就可以了嗎熏迹,然后接產生了解決方案一:
解決方案一:獲取事件觸發(fā)的實際目標(target)
-
我給事件處理函數添加了事件參數e,獲取到了e.target凝赛,然后對e.target的特征(class)進行了判斷注暗,判斷如果是內層div就不進行事件觸發(fā),確實達到了我想要的效果墓猎,代碼如下:
-
后來發(fā)現(xiàn)并沒有解決實際的問題捆昏,假如有很多個內層div,并且每一個div的class都是不一樣的毙沾,或者內層div里面又有嵌套元素的話這個方法就不生效了:
于是我又想到前兩天學習了一下關于DOM事件傳播的機制骗卜,在DOM2級事件流中包含事件捕獲和事件冒泡兩個階段,其中觸發(fā)事件處理程序時左胞,事件傳播先是進入事件捕獲階段寇仓,事件由外層向內層具體元素傳播,然后進入事件冒泡階段烤宙,由內層具體元素再向外層進行傳播遍烦,事件的處理默認是在冒泡階段,如下圖所示:
其中event對象中有一個方法是stopPropagation()
躺枕,可以利用這個方法阻止事件的傳播服猪,然后我就想著能不能用用這個方法來阻止事件的捕獲,在容器ct的點擊處理程序上添加stopPropagation()
拐云,addEventListener
第三個參數設置為true罢猪,讓事件處理發(fā)生在容器ct的捕獲階段,不向更具體的內層元素進行傳播叉瘩,結果發(fā)現(xiàn)我又踩坑了:原因是事件捕獲是不能被阻止的膳帕,否則定位不到具體的元素;
那么只能采用阻止事件冒泡的方法來達成效果薇缅,于是出現(xiàn)了解決方案二:
解決方案二:阻止事件冒泡
首先理順一下思路危彩,因為我不想容器ct的子元素觸發(fā)容器ct的事件,所以當我點擊容器ct子元素時捅暴,事件進入捕獲階段恬砂,傳播路徑如下:
Document → html → body → div#ct → div.a → div.c
然后是冒泡并且執(zhí)行處理方法的階段:
div.c(觸發(fā)ct事件) → div.a(觸發(fā)ct事件) → div#ct(觸發(fā)ct事件) → body → html → Document
理清了這個思路后問題就變得簡單了,我們只要獲取到了ct子元素div.a蓬痒,然后給它單獨添加stopPropagation()
阻止事件冒泡泻骤,與此同時容器ct本身的事件觸發(fā)不變動,就能達成效果梧奢,代碼如下:
這樣子就能徹底解決方案一所出現(xiàn)的問題了狱掂。