一、这是需要实现的效果
功能描述:
-
鼠标移入导航,下方显示对应的菜单;
-
鼠标移出导航,隐藏下方对应的菜单;
-
当下方菜单显示后,鼠标移入没有变化;
-
当鼠标移出下方的菜单,菜单进行隐藏;
如图所示:
二、下面是我实现的代码(有bug):
bug1 向各位侠客献上:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
*{
margin: 0;
padding: 0;
}
.header{
height: 60px;
line-height: 60px;
background-color: #ccc;
}
.header ul {
margin-left: 100px;
}
ul > li{
float: left;
padding: 0 10px;
margin-left: 20px;
list-style: none;
cursor: pointer;
}
ul > li:hover{
color: #fff;
background-color: #000;
}
.menu{
position: absolute;
left: 172px;
top: 60px;
width: 100px;
/* height: 120px; */
padding: 10px;
text-align: center;
background-color: #fff;
border: 1px solid #000;
display: none;
}
.menu p:first-child{
border-top: none;
}
.menu p{
display: block;
width: 100%;
height: 36px;
line-height: 36px;
background-color: red;
border-top: 1px solid #000;
}
</style>
</head>
<body>
<div class="header">
<ul>
<li>首页</li>
<li>分类</li>
<li>特价</li>
</ul>
<div class="menu">
<p>女装</p>
<p>男装</p>
<p>手机</p>
<p>电子设备</p>
</div>
</div>
<script src="jquery.min.js"></script>
<script>
$(function(){
$(".header li:nth-child(2)").mouseenter(function(){
$(".menu").stop().slideDown();
})
$(".header li").mouseleave(function(){
$(".menu").stop().slideUp();
})
$(".menu").mouseenter(function(e){
console.log("移入");
$(".menu").stop().slideDown();
})
$(".menu").mouseout(function(e){
console.log("移出");
$(".menu").stop().slideUp();
})
})
</script>
</body>
</html>
bug1 描述:
-
鼠标移入导航栏,也就是“分类”文字中,此时显示下方菜单。
-
当鼠标移入下方菜单的白色区域,触发移入事件控制台打印“移入”。
-
当鼠标移入红色区域,此时就触发了移出事件,控制台打印“移出”,下拉菜单隐藏。
-
------这显然不是我们想要的效果!------
-
我们想要的是鼠标移入下拉菜单中(黑色边框、白色部分、红色部分)也不会隐藏,当鼠标移出“下拉菜单”和“分类”中才进行隐藏。
接着 bug2 就诞生了!
bug2 向各位侠客献上:
(html 和 css 没有修改,下面是修改后的 js 代码。需要 html 和 css 代码的上面有。)
$(function(){
$(".header li:nth-child(2)").mouseenter(function(){
$(".menu").stop().slideDown();
})
$(".header li").mouseleave(function(){
$(".menu").stop().slideUp();
})
// mouseenter 修改为:mouseover
$(".menu").mouseover(function(e){
console.log("移入");
$(".menu").stop().slideDown();
})
$(".menu").mouseout(function(e){
console.log("移出");
$(".menu").stop().slideUp();
})
})
bug2 描述:
-
鼠标移入红色部分的问题也解决了,看着没什么问题;
-
但是你们看控制台,当我鼠标来回在红色部分移动的时候,控制台一直在打印移入移出,也就是说,一直在触发移入移出事件。
-
接着我清除了 js 中所有 stop() 的地方( stop() 是 jQuery 中封装的,功能为:停止所有在指定元素上正在运行的动画。)
-
删除后:
-
$(function(){ $(".header li:nth-child(2)").mouseenter(function(){ $(".menu").slideDown(); }) $(".header li").mouseleave(function(){ $(".menu").slideUp(); }) $(".menu").mouseover(function(e){ console.log("移入"); $(".menu").slideDown(); }) $(".menu").mouseout(function(e){ console.log("移出"); $(".menu").slideUp(); }) })
-
引出问题:
-
为什么我们把 stop() 删除后,页面中的菜单就来回切换。但是控制台的输出 bug2 描述一样,来回触发移入移出事件。
-
原因:
- 当鼠标移入菜单红色部分的时候,触发了移出事件,此时会把元素进行隐藏(向上移动)。
- 这个时候鼠标接触到的是 body,那么我们给菜单绑定的事件是 mouseover ,mouseover 有冒泡行为,菜单的父元素是 body ,body 也就有了鼠标移入事件。此时触发移入事件,菜单又显示到页面,鼠标又接触到红色部分,又进行隐藏,鼠标又接触到 body ,又触发移入事件,进行循环触发移入移出事件,所以就成了这个效果。
- bug2 为什么不会来回隐藏,是因为被 stop() 关闭了动画,实际上也在执行移入移出事件。
三、解决方案
在解决这个 bug 之前,大侠们一定要把基本功打牢。(要理解下面的事件和冒泡)
我就是基本功不扎实,经常踩坑。
代码献上:
$(function(){
$(".header li:nth-child(2)").mouseenter(function(){
$(".menu").stop().slideDown();
})
$(".header li").mouseleave(function(){
$(".menu").stop().slideUp();
})
// mouseover 修改后:mouseenter
$(".menu").mouseenter(function(e){
console.log("移入");
$(".menu").stop().slideDown();
})
// mouseout 修改后:mouseleave
$(".menu").mouseleave(function(e){
console.log("移出");
$(".menu").stop().slideUp();
})
})
描述:
- 因为 mouseover 和 mouseout 有冒泡行为,会依次向父元素绑定事件。修改成没有冒泡的 mouseenter 和 mouseleave 即可解决。
- 大家别忘了在动画或效果的前面加上 stop() 。(解决多次触发事件,动画排队的问题)