做二級選單時候遇到的關於事件冒泡以及mouseover和mouseenter的不同
阿新 • • 發佈:2018-12-17
二級選單作為最普通小元件,我遇到了坑.
1 <style> 2 .wrapper { 3 height: 150px; 4 border: 1px solid; 5 width: 150px; 6 } 7 8 .wrapper>div { 9 height: 48px; 10 width: 150px; 11 border: 1px solid; 12 text-align: center;var father = document.getElementsByClassName( 'father'); for ( let i = 0; i < father.length; i ++) { father[ i]. onmouseover = function(){ var son = father[ i] .getElementsByTagName( 'div')[ 0]; son.style.display = 'block'; } father[ i]. onmouseleave = function(){ var son = father[ i] .getElementsByTagName( 'div')[ 0]; son.style.display = 'none'; } 以上的程式碼是可以實現效果的,滑鼠移入會出現son,滑鼠一出會son不見, 但是下面的就不可以了. 下面的滑鼠一旦移動那個出father,進到son區域後,son區域會消失,也就是不可以點到son,沒法用. father[ i]. onmouseenter = function(){ var son = father[ i] .getElementsByTagName( 'div')[ 0]; son.style.display = 'block'; } father[ i]. onmouseout = function(){ var son = father[ i] .getElementsByTagName( 'div')[ 0]; son.style.display = 'none'; } 沒法用的原因是因為定義在父級上的mouseenter事件和大多數事件 不一樣,不會傳播給兒子,我這樣理解是和官方不一樣的.不過不影響結果. 而mouseover事件會傳播給兒子;在看一個例子就知道了: 兩個父子div.父div上繫結click事件 father.onclick = function(){console.log(1111)} 然後點選子div,也會觸發事件,輸出1111;這官方的解釋是:點選的是son,在son上觸發了click事件,事件是冒泡的,會傳播給父級,父級上綁定了事件函式,從而導致事件函式的執行. ( 但是我覺得這樣理解不好,因為很簡單的原因:son也是father 的一部分,son上觸發就等於father上觸發啊,觸發事件自然執行函式.這樣比較容易理解.且根本不會有執行順序上的問題,因為son上沒繫結函式) 但此時你如果把click換成mouseenter,點選son它不好使了,不輸出111,只有點選非son的father部分它才好使. 官方就把從son到father的事件傳播叫做事件冒泡,把這種人為或者非人為的方式來達到不往上傳播的手段叫做阻止事件冒泡 .也就是說,mouseover事件不會向上傳播,自帶阻止事件冒泡的功能. 按照官方的說法,則必須把元素在頁面的結構理解為:子元素一定在父元素上面,點選子元素所在父元素區域即點選子元素而非父元素,只是子元素事件大部分可以冒泡,然後達到父元素.(只有這麼理解才能解釋的通) 按我的理解就是,子屬於父,點選子就是點選父.好比父是一個國家中國,子是他下面的省黑龍江.滑鼠是美帝的炮彈,當一顆炮彈達到黑龍江,難道不是打到了中國?有點禿嚕了... 這種事件冒泡會有好處,也會有壞處,好處要利用,壞處要防止發生.就行用人一樣 點選實現出現二級選單. father[ i]. onclick = function ( e) { e .stopPropagation()//注意這一行 var son = document.getElementsByClassName( 'son'); for ( var j = 0; j < son.length; j ++) { if ( j == i) { son[ j].style.display = 'block'; } else { son[ j].style.display = 'none' } } } } document. onclick = function ( e) { var son = document.getElementsByClassName( 'son'); for ( var k = 0; k < son.length; k ++) { son[ k].style.display = 'none' } } 當我們點選father時候,如果沒有e.stopPropagation()這一行,現象是會不出現效果.原因是:當點選father時候,document是father的父級,即觸發了document事件. 按照官方的解釋:事件冒泡是有順序的,總是子冒泡到父;點選了子,子事件綁定了函式,函式執行,在冒泡到父,父的事件上綁定了函式,則,函式又執行.最終結果,子選單沒出來. 這時候,如果想實現效果,就必須在該事件觸發時,不讓子事件傳播到父,則需要加上那麼一行: e .stopPropagation (); 總之,最重要的是記住這種預設的父子結構:子總在父上面,且子總是愛將事件傳給父如果不阻止的話!!!!!13 line-height: 48px; 14 cursor: pointer; 15 position: relative; 16 17 } 18 19 .son { 20 display: none; 21 position: absolute; 22 left: 150px; 23 top: 0px; 24 border: 1px solid; 25 height: 150px;26 width: 150px; 27 } 28 29 .son>div { 30 height: 48px; 31 width: 100%; 32 text-align: center; 33 line-height: 48px; 34 cursor: pointer; 35 border: 1px solid; 36 } 37 </style> 38 </head> 3940 <body> 41 42 <div class="wrapper"> 43 <div class="father string">string 44 <div class="son string-son"> 45 <!-- 為什麼要設定成父子關係?????因為設成兄弟元素,mouseover事件並不能作用在son上,也就不能滑鼠移到它身上時候還能有父的mouseover事件 --> 46 <!-- mouseover事件和mouse --> 47 <div>one</div> 48 <div>two</div> 49 <div>three</div> 50 </div> 51 </div> 52 <div class="father boolen">boolen 53 <div class="son boolen-son"> 54 <div>true</div> 55 <div>false</div> 56 </div> 57 </div> 58 <div class="number father">number 59 <div class="son number-son"> 60 <div>1</div> 61 <div>2</div> 62 </div> 63 </div> 64 </div>