本文探索一下Event的冒泡過程和初學遇到的幾個小bug
Event接口是檢測在DOM中的發生的全部事件,咱們一直在用,並且從DOM的很早的版本就一直在用着。早期的網景(後來的火狐)和IE是各自爲戰,直到W3C一統江湖,DOM版本一路發展而來,經歷了DOM-0(洪荒時代)、DOM-1(只有兩章核心內容)、DOM-2(劃時代的一個版本,咱們學的Event就在這個版本,並且目前的用的也是這個版本)、DOM-三、DOM-4(草案階段)。javascript
//一、有一個js函數以下 function print(){ console.log(1) } //二、在html的button裏面點擊觸發上面的函數 <button id=button onclick="?">點我</button> //問號處填能夠填什麼 A. print() B.print C.print.call() //在js裏面的onclick裏面觸發 button.onclick = ? //問號處能夠填什麼 A. print() B.print C.print.call()
A
C
,第二個問號應該選B
()
的,而第二處在JS中,onclick是一個屬性,不須要馬上執行,等用戶點擊了,瀏覽器再反應,不須要()
。既然onclick
等on事件在JS中是一個屬性,那麼後面的就會覆蓋前面的,因此DOM2裏面引入了一個重要的EventListener
,是一個隊列。css
這是一個隊列,例子1,先進先出的特色,爲後面的冒泡模型作準備。html
function f(){ console.log("eventListener不會覆蓋") } button2.addEventListener('click', function(){ console.log("eventListener不會覆蓋1") }) button2.addEventListener('click', f) button2.removeEventListener('click', f) button2.addEventListener('click', function(){ console.log("eventListener不會覆蓋3") })
eventListener不會覆蓋1
eventListener不會覆蓋3
remove
來實現one
執行一次的操做function f(){ console.log("eventListener不會覆蓋2") button2.removeEventListener('click', f) } button2.addEventListener('click', f)
只會打印一次,不會一直打印了,也就是one
的原理。java
上面的官方文檔中,我只研究一下捕獲階段(capture phase)和冒泡階段(bubbling phase)。git
grand.addEventListener('click', function(){ console.log('我是你爺爺') }) dad.addEventListener('click', function(){ console.log('我是你爸爸') }) son.addEventListener('click', function(){ console.log('我是你兒子') })
這是三個div
的事件,當你點擊的時候,控制檯打印必然會有順序。那麼應該是什麼順序呢,正常人的思惟不外乎兩種結果github
grand.addEventListener('click', function(){ console.log('我是你爺爺') }, true) dad.addEventListener('click', function(){ console.log('我是你爸爸') }, true) son.addEventListener('click', function(){ console.log('我是你兒子') }, true)
addEventListener
後面的參數決定了順序,當你不寫的時候是undefined
,也就是false
的意思。複習一下五個falsey
值瀏覽器
0
NaN
''
null
undefined
除此以外都是true
上圖是簡單的圖解,注意優先運行爲true
的部分,再運行false
的部分。app
簡單的實例====================>demodom
grand.addEventListener('click', function(){ console.log('我是你爺爺') }, true) dad.addEventListener('click', function(){ console.log('我是你爸爸') }) son.addEventListener('click', function(){ console.log('我是你兒子')
true
,先打印誰,都是false
,繼續按照冒泡順序打印。son.addEventListener('click', function(){ console.log('我是你兒子true') }, true) son.addEventListener('click', function(){ console.log('我是你兒子false') })
false
true
,應該打印什麼呢
parent
是關鍵字不能使用,一不當心使用的話會出問題。異步
div
的display是block,點擊其餘地方變爲none。很快你會碰到了第一個bug
正常來講,應該點擊body控制檯打印數字1,你點爛了你的羅技鼠標也沒出來。爲何呢?
使用了紅色border以後,發現body的高度過矮了,點擊不到啊。
很好,你進入了第二個bug了
根據圖片 中的控制檯能夠發現,確實都點擊到了,監聽沒問題,並且點擊後,也是按照冒泡的順序打印的結果。
註釋掉出問題的代碼後,上圖是正常的點擊出現對話框啊,說明問題就出在註釋的代碼上。
div
,以後,往 body
document
上冒泡,在document
上馬上被殺死,display變爲none,你作夢能看到 彈出框啊。
咱們既然知道了第二個bug產生的緣由,那麼咱們阻止冒泡順序
clickMe.addEventListener('click', function(){ popover.style.display = 'block' console.log('點擊浮層了') }) wrapper.addEventListener('click', function(e){ e.stopPropagation() }) document.addEventListener('click', function(){ popover.style.display = 'none' console.log('點擊文檔了') })
$(clickMe).on('click', function(){ $(popover).show() console.log('show') setTimeout(function(){ console.log('one click') $(document).one('click', function(){ console.log('我覺的他不會執行') $(popover).hide() }) },0) }) // $(wrapper).on('click', function(e){ // e.stopPropagation() // }) $(document).on('click', function(){ console.log('走到document啦') })
show()
hide()
JS版本的節省內存的版本==================>節省內存
jQuery版本的節省內存版本=================>jQuery節省內存
.popover{ display: inline-block; border: 1px solid red; position: relative; padding: 10px; margin:10px; } .popover::before{ position: absolute; content: ''; top: 5px; right: 100%; border: 10px solid transparent; border-right-color:red; } .popover::after{ content: ''; border: 10px solid transparent; position: absolute; right: 100%; top: 5px; border-right-color: white; margin-right: -1px; }
主要利用boder-right-color
以及兩個僞元素。
浮層三角的實例=============================>demo
點擊一下會有驚喜的https://github.com/codevvvv9/bubble/blob/master/bubble.gif