二级菜单作为最普通小组件,我遇到了坑.
1 <style> 2 .wrapper { 3 height: 150px; 4 border: 1px solid; 5 150px; 6 } 7 8 .wrapper>div { 9 height: 48px; 10 150px; 11 border: 1px solid; 12 text-align: center; 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 150px; 27 } 28 29 .son>div { 30 height: 48px; 31 100%; 32 text-align: center; 33 line-height: 48px; 34 cursor: pointer; 35 border: 1px solid; 36 } 37 </style> 38 </head> 39 40 <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>
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();
总之,最重要的是记住这种默认的父子结构:子总在父上面,且子总是爱将事件传给父如果不阻止的话!!!!!