js和jquery下拉菜单全攻略

我们先看看利用javascript如何实现下拉菜单。

下拉菜单的效果是当鼠标滑过主菜单的时候,二级菜单显示,而当鼠标滑过的时候,二级菜单隐藏。网上实现的方法很多,我觉得最好的是下面这个,因为它不需要在html代码中给标签注册一个事件函数。实现了行为和内容的完全分离。

html代码:

<ul id="nav">
   <li><a href="#">首页</a></li>
    <li><a href="#">首页</a>
         <ul>
             <li><a href="#">二级菜单</a></li>
              <li><a href="#">二级菜单</a></li>
               <li><a href="#">二级菜单</a></li>
                <li><a href="#">二级菜单</a></li>     
        </ul>
    </li> 
     <li><a href="#">首页</a></li>
      <li><a href="#">首页</a></li>

</ul>

 

css代码:

 

 

*{ margin:0; padding:0;}
#nav{ width:850px; margin:20px auto;}
a{ color:#FFF; text-decoration: none;}
ul,li{ float:left;list-style:none; font-size:14px; width:60px; background:#690; color:#FFF;}
li{ float:left; width:60px;height:30px; line-height:30px;  position:relative; }
ul li ul{ display:none;position:absolute; top:30px; left:0px;}
ul li.over ul{ display:block; }

 

 

 

 

 

js代码:

function test()
{
 var LiTag=document.getElementById("nav").getElementsByTagName("LI");   //获取主菜单的li;
   for(var i=0;i<LiTag.length;i++)  //历遍主菜单的li
   {
   LiTag[i].onmouseover=function()   //给主菜单注册一个onmouseover事件,当鼠标滑过的时候
   {
               this.className="over";    //当前li设置一个名为"over"的class,此class表示当li下的ul的css display值为block即显示
      }  
   LiTag[i].onmouseout=function()  ////给主菜单注册一个onmouseout事件,当鼠标移开的时候
      {        this.className="";          //当前li清除一个名为"over"的class,此时ul为恢复的display:none
      }   
   }
}

window.onload=test;

 

 

我们还有第二种方法,思路其实差不多

function test()
{
 var navTag=document.getElementById("nav"); 
   var nodeTage=navTag.getElementsByTagName("li"); 
   for(var i=0;i<navTag.childNodes.length;i++)
   {    
         var node = navTag.childNodes[i];
     //LI需要大写
  if(node.nodeName=='LI')
  {  
    node.onmouseover=function() 
    {   this.className="over";
    }

    //移开是onmouseout
    node.onmouseout=function() 
    {   this.className="";
    }
  } 
    
  }
}

 

不过其中有一点要注意:node.nodeName=='LI'中标签li一定要大写。否则程序无法工作。或者我们通过toLoweCase()方法来实现li转化成LI,也就是把这行代码 if(node.nodeName=='LI')写成if(node.nodeName.toLowerCase=='LI')

接下来我们看看第三种方法:

前两种方法我们都把主菜单的li作为主体对象进行操作,在主菜单的li历遍的时候,通过改变li的class来实现其子对象ul的隐藏和显示。第三种方法我们将li下的ul作为操作对象。直接控制它的隐藏和显示。(css和html代码不变)

function test()
{
 var LiTag=document.getElementById("nav").getElementsByTagName("LI");
 //var ulNode=LiTag.getElementsByTagName("ul")[0];
 
  // var nodeTage=navTag.getElementsByTagName("li");
   
   for(var i=0;i<LiTag.length;i++)
   {
   LiTag[i].onmouseover=function()                                    //给所有的主菜单li注册鼠标滑过事件
   {
              if(this.getElementsByTagName("ul").length>0)    //如果当前li下存在ul的话
     {
             this.getElementsByTagName("ul")[0].style.display="block"  //先获取到当前li下的ul对象然后让它显示
      
     }
      }
   
   LiTag[i].onmouseout=function()                                            //给所有的主菜单li注册鼠标滑过事件
      {        if(this.getElementsByTagName("ul").length>0)         //如果当前li下存在ul的话
     {     
            this.getElementsByTagName("ul")[0].style.display="none"   //先获取到当前li下的ul对象然后让它隐藏
     }
      
      } 
  
   }
}

 

 这里有一点要注意的是:this.getElementsByTagName("ul").length>0 和this.getElementsByTagName("ul")[0].style.display="block"

这里的this指的是当前的li。不能写成 LiTag[i].onmouseout=function()

{ if(LiTag[i].getElementsByTagName("ul").length>0) //如果当前li下存在ul的话 {
LiTag[i].getElementsByTagName("ul")[0].style.display="none" //先获取到当前li下的ul对象然后让它隐藏 } 因为LiTag[i]是一个数组,而this是一个具体的li对象,是当前的对象。如果写成LiTag[i],则会提示undefined

===================================================================

===================================================================

下面我们来利用jquery制作这种效果:

主要思路:利用jquery的slideDown()和slideUp()----改变高度来实现。

1  html代码

<div id="box">
  <ul class="menu">
    <li><a href="#">网易</a>
      <ul>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">小组</a></li>
      </ul>
    </li>
    <li><a href="#">相册</a></li>
    
    <li><a href="#">博客</a></li>
    <li><a href="#">邮箱</a>
      <ul>
        <li><a href="#">163邮箱</a></li>
        <li><a href="#">126邮箱</a></li>
        <li><a href="#">yeah.net</a></li>
      </ul>
    </li>
    <li><a href="#">小组</a></li>
  </ul>
</div>

 

2  css代码:

<style>
* { margin:0; padding:0;}
body {font-family:Verdana, Geneva, sans-serif;font-size:14px;}
ul, li {list-style:none;}
a, a:visited { text-decoration:none;display:block;}
#box {width:520px;margin:20px auto;}
.menu {width:520px;}
.menu li {float:left;text-align:center;margin-right:2px;position:relative;}
.menu li a { background:#693;color:#FFF;font-weight:bold;width:100px; height:30px;line-height:30px;}
.menu li ul {position:absolute;left:0;top:30px;display:none}
.menu li ul li a { width:100px; padding-bottom:5px; background:#693;} 
.menu li ul li a:hover{ background: #CBCD85; color:#000;} 

 

3  jquery代码

 

$(function(){
     
$(".menu li").hover(function (){   
   $(this).find("ul").slideDown();
   },function(){       
   $(this).find("ul").slideUp()            
  })

})

 

ok,现在基本效果已经出来了。但是美中不足的是,当我们在主菜单上快速移动时,下拉菜单会像弹簧一样弹来弹去,而且会弹三四下才会最终缩回去。原因在哪里???

原因在于我们在我们快速移动时,会使得slideDown()和slideUp()以很快的速度频繁触发,而前一个动画还没执行完,下一个又开始了,从而导致了动画的积压。

解决办法:

1 在动画执行前我们运用一个stop()方法。stop()里面两个参数都是布尔值,前一个代表是否要清空未执行完得动画队列,后一个表示是否直接将只在执行的动画跳转到末状态,如果直接使用stop()方法,会立即停止正在进行的动画。

更改jquery代码:

$(function(){
     
$(".menu li").hover(function (){   
   $(this).find("ul").stop(true,true).slideDown();
   },function(){       
   $(this).find("ul").stop(true,true().slideUp()            
  })

})

 

2  我们只要确定在执行slideDown()和slideUp()之前没有动画执行,就不会产生积压,因此,我们可以利用jquery的过滤器过滤动画

更改jquery代码:

$(function(){
     
$(".menu li").hover(function (){   
   $(this).find("ul").filter(":not(:animated)").slideDown();
   },function(){       
   $(this).find("ul").filter(":not(:animated)").slideUp()            
  })

})

 

趁热打铁:我们可不可以用这个特效模拟出类似牛图库首页的效果:如图

jquery下拉菜单全攻略 - 睡觉青蛙 -              sean
接下来我们试试:
 

 由于下拉菜单下内容比较多,我们给下拉菜单里的ul设置一个比较大的宽度,同时在里面多添加几个li。html代码:

<div id="box">
  <ul class="menu">
    <li><a href="#">网易</a>
      <ul>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">小组</a></li>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">小组</a></li>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">小组</a></li>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
        <li><a href="#">小组</a></li>
        <li><a href="#">新闻</a></li>
        <li><a href="#">微博</a></li>
      </ul>
    </li>
    <li><a href="#">相册</a></li>
    <li><a href="#">博客</a></li>
    <li><a href="#">邮箱</a>
      <ul>
        <li><a href="#">163邮箱</a></li>
        <li><a href="#">126邮箱</a></li>
        <li><a href="#">yeah.net</a></li>
      </ul>
    </li>
    <li><a href="#">小组</a></li>
  </ul>
</div>

 

css代码只需要对.menu li ul和ul里的li以及a做设置即可

.menu li ul{position:absolute;width:320px;left:0;top:30px;display:none}

.menu li ul li { float:left;}
.menu li ul li a {padding-bottom:5px;display:inline;background: #FFF; color:#09F;}  

.menu li ul li a:hover {background: #CBCD85;color:#000;}

 

js代码不变

这个效果在IE和易IE为内核的浏览器都可以正常显示,但是在ff和web-kit内核的浏览器却出现这样的问题:

当我把鼠标移动到下拉菜单的链接上时,整个下拉菜单出现了,但是当我再把鼠标移动到下拉菜单的第二个连接上时。整个下拉菜单却以很快的速度消失了。那么问题出现在哪里?

是不是下拉菜单的a元素的问题?我把下拉菜单的a设置了一个和主菜单一样的宽度。.menu  li ul li a:{dispalyblock;width:100px;margin:0;}。现在虽然勉强可以了,但是.menu  li ul 我们设置了一个较大的宽度,所有的a横向排满之后还有一个一些空,当我们把鼠标移动到空上时,问题又出来了,整个下拉菜单又以很快的速度隐藏了。那么问题到底出现在哪里?

无奈之下,我打算给.menu  li ul设置一个背景色,奇了.........现在问题解决了。

css代码:

.menu li ul { position:absolute; width:320px;

background: #993; /*这里是问题所在*/

left:0;top:30px; display:none
}
.menu li ul li { float:left;}
.menu li ul li a {padding-bottom:5px;display:inline;background: #FFF; color:#09F;}  

.menu li ul li a:hover {background: #CBCD85;color:#000;}

 

通过测试ie和其他的浏览器,居然都可以显示。至于原因,尚不清楚。可能是一个bug////

最后效果:

jquery下拉菜单全攻略 - 睡觉青蛙 -              sean
jquery下拉菜单全攻略 - 睡觉青蛙 -              sean

 

 配色特难看,望见谅,如果我们把下拉菜单的颜色和主菜单颜色设置一样的话,效果就和牛图库首页一样 ,自己改下吧。O(∩_∩)O哈哈~

GO on,我们再看看另外一个菜单效果:

jquery下拉菜单全攻略 - 睡觉青蛙 - sean

 这是一个很有意思的菜单,当鼠标滑过的时候。会出现一个小三角形。接着菜单出现了。这个效果如何做到呢?其实和上面的原理是一样的。只是有一点细微的区别。就是我们在下拉菜单的ul里面添加了一个三角形的小图片。然后通过定位让它固定在某个地方。初始状态时隐藏的,而当鼠标滑过的时候则显示:

由于有一个三角图标,因此html代码要稍微改动一下:

html代码:

<body>
<ul id="menu">
  <li><a href="#">menu</a>
    <ul>
    <img src="arroe.gif"/>      <!--在ul里插入一个img标签-->
      <li><a href="#">sec_menu</a></li>
      <li><a href="#">sec_menu</a></li>
      <li><a href="#">sec_menu</a></li>
      <li><a href="#">sec_menu</a></li>
     </ul>
  </li>
  <li><a href="#">menu</a></li>
  <li><a href="#">menu</a></li>
  <li><a href="#">menu</a></li>
</ul>
</body>

 

css代码:

<style>
*{ margin:0; padding:0; font-size:14px; font-family:Verdana, Geneva, sans-serif;}
a,a:visited{text-decoration:none;}
ul,li{ list-style:none;}
#menu{ width:420px; margin:20px auto;}
#menu li{ float:left; position:relative;width:100px; height:30px; line-height:30px; text-align:center;}
#menu li a{ background: #690; color:#FFF;   display:block; font-weight:bold; border-right:1px solid #FFF; }
#menu li a:hover{ background: #660;}
#menu li ul{ width:500px; background: #060; position:absolute; top:40px; left:0px; border:#693 1px solid; height:40px; display:none; }

 

 

 #menu li img{ position:absolute; top:-15px; left:20px; disblok:none;}    <!--图片位于ul下,是ul的子元素。由于ul已经设置为绝对定位,顺便说一下,我们也可以把img放在ul之上,和ul是兄弟元素,然后设置定位,此时img定位的基准就不在是ul了,而是它的父元素li即主菜单。--> #menu li ul li a{ color:#FFF; background:#060; display:inline; border:none; }

</style>

 接下来是jquery代码:我们要实现的效果是当鼠标滑过主菜单时,下拉菜单和三角形小图标都出来了。所以我们代码好像和上一个例子jquery下拉菜单全攻略 - 睡觉青蛙 -              sean是一样的。

 

代码:

<script src="jquery-1.5.1.min.js"></script>
<script>
$(function(){
    $("#menu li:has(ul)").hover(function(){
  $(this).filter(":not(:animated)").find("img").show()
  $(this).children("ul").filter(":not(:animated)").slideDown(100);
     },function(){
    $s.children("ul").filter(":not(:animated)").slideUp(100)       
   $s.filter(":not(:animated)").find("img").hide()  

  });    
 })

</script>

 

 效果是出来了,但是有一个问题:当我们下拉菜单出现的时候如果我们想从下拉菜单和主菜单之间的缝隙间滑过想去点击下拉菜单里的链接的话,整个下拉菜单就会很快的隐藏掉。这个该如何处理?关于这个问题我咨询了《锋利的jquery作者》单东林,他给我的解决方案是用一个js延迟处理函数来处理鼠标划入时的事件。感谢他的热心帮助

 我们知道javascript里有两个延迟处理的函数:setInterval(fucntion(),设置时间比如200)(有循环)——对应的清除函数clearInterval(),()和setTimeout(functon(),200)(只进行一次,无循环————对应的清除函数clearInterval()。下拉菜单我们这里用到setTimeout(functon(),200),因为我们只需要在鼠标滑过的时候让他出现即可。既然是快速鼠标稍微离开就快速隐藏,那么我们就让鼠标移除时让它延迟一定的时间。这样在下拉菜单和主菜单的空白处滑动鼠标时下拉菜单就不会立刻隐藏。而鼠标移除后清除它:

$(function(){
  
  var $time = null;
    $("#menu li:has(ul)").hover(function(){
  window.clearTimeout($time);  //鼠标滑过的时候让延迟的动作移除。这个window可以除掉,写成clearTimeout即可
  $(this).filter(":not(:animated)").find("img").show();; 
  $(this).children("ul").filter(":not(:animated)").slideDown(100);
  return false;
     },function(){
  var $s = $(this)   //这个地方特别要注意。如果不获取this对象。直接写$(this),此时的this就不再是主菜单上的li了(即$("#menu li:has(ul)"))而是整个window对象了。所以我们要事先捕获到主菜单里的li。
  $time = setTimeout(function(){
   $s.children("ul").filter(":not(:animated)").slideUp(100)       
   $s.filter(":not(:animated)").find("img").hide();
  },500);       //鼠标移出的时候。让下拉菜单停一会儿,做个延迟处理。不让它立刻就隐藏
  return false;     
   });    
   //对ul进行操作      //这里对下拉菜单的ul也进行了设置。其实没有这一步,我们要达到的目的(不让鼠标在移出的时候整个下拉菜单快速隐藏)基本上实现了,但是我们对ul进行处理的时候,最终就是我们要达到的最佳效果了
   $("#menu li ul").hover(function(){
  window.clearTimeout($time);
   },function(){
  $(this).slideUp(100);
  $(this).find("img").hide();
   });
})

</script>


 

 

 ps:再啰嗦一下:我这个实例中的小三角形是一张图片。我们同样可以不用图片而用css来实现。但是要加入一个新的块级元素。设置heigh=0;width=0;border设置一个值,然后对bored-left,border-right,border-top和border-bottom设置即可。下次有时间再做

ok,继续趁热打铁。这是二级菜单,那么三级菜单呢?让我们再试试吧

1构建html代码:

<ul id="nav">
  <li><a href="">Title 1</a>
    <ul class="children">
      <li><a href="">Child List 1</a></li>
      <li><a href="">Child List 2</a></li>
      <li><a href="">Child List 3</a></li>
      <li><a href="">Child List 4</a></li>
      <li><a href="">Child List 5</a></li>
    </ul>
  </li>
  <li><a href="">Title 2</a>
    <ul class="children">
      <li><a href="">Child List 1</a></li>
      <li><a href="">Child List 2</a></li>
      <li><a href="">Child List 3</a></li>
      <li><a href="">Child List 4</a></li>
      <li><a href="">Child List 5</a></li>
    </ul>
  </li>
  <li><a href="">Title 3</a>
    <ul class="children">
      <li><a href="">Child List 1</a></li>
      <li><a href="">Child List 2</a></li>
      <li><a href="">Child List 3</a></li>
      <li><a href="">Child List 4</a></li>
      <li><a href="">Child List 5</a></li>
    </ul>
  </li>
  <li><a href="">Title 4</a>
    <ul class="children">
      <li><a href="">Child List 1</a></li>
      <li><a href="">Child List 2</a></li>
      <li><a href="">Child List 3</a></li>
      <li><a href="">Child List 4</a></li>
      <li><a href="">Child List 5</a></li>
    </ul>
  </li>
  <li><a href="">Title 5</a>
    <ul class="children">
      <li><a href="">Child List 1</a>
        <ul class="children">
          <li><a href="">Child List 1</a>
            <ul class="children">
              <li><a href="">Child List 1</a></li>
              <li><a href="">Child List 2</a></li>
              <li><a href="">Child List 3</a></li>
            </ul>
          </li>
          <li><a href="">Child List 2</a>
            <ul class="children">
              <li><a href="">Child List 1</a></li>
              <li><a href="">Child List 2</a></li>
              <li><a href="">Child List 3</a></li>
            </ul>
          </li>
          <li><a href="">Child List 3</a>
            <ul class="children">
              <li><a href="">Child List 1</a></li>
              <li><a href="">Child List 2</a></li>
              <li><a href="">Child List 3</a></li>
            </ul>
          </li>
        </ul>
      </li>
      <li><a href="">Child List 2</a>
        <ul class="children">
          <li><a href="">Child List 1</a></li>
          <li><a href="">Child List 2</a></li>
          <li><a href="">Child List 3</a></li>
        </ul>
      </li>
      <li><a href="">Child List 3</a>
        <ul class="children">
          <li><a href="">Child List 1</a></li>
          <li><a href="">Child List 2</a></li>
          <li><a href="">Child List 3</a></li>
        </ul>
      </li>
      <li><a href="">Child List 4</a>
        <ul class="children">
          <li><a href="">Child List 1</a></li>
          <li><a href="">Child List 2</a></li>
          <li><a href="">Child List 3</a></li>
        </ul>
      </li>
      <li><a href="">Child List 5</a>
        <ul class="children">
          <li><a href="">Child List 1</a></li>
          <li><a href="">Child List 2</a></li>
          <li><a href="">Child List 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

 

 

看起来貌似很多,接下来是css代码

<style type="text/css">
body {background: #F9F9F9;font-family: Verdana, Tahoma, Arila, Helvetica; font-size: 0.75em;}
ul {margin: 0; padding: 0; color: #333;}
a, a:visited {display: block; color: #FFFFFF; padding: 5px 20px; text-shadow: 1px 1px 0 #63843E; text-decoration: none; background: #8FB665;}
a:hover {text-decoration: none; background: #7BA54E; color: #F2F2F2;}
#nav {height: 30px; width: 500px; margin: 100px auto;}
#nav li {float: left; list-style: none; position: relative;}
#nav li ul {display: none; width: 100px; background: none; position: absolute; left: 0;}
#nav li li a, #nav li li a:visited {padding: 10px 12px; background: #7BA54E; float: left;}
#nav li li a:hover {background: #8FB665;}
#nav li ul ul {left: 100%; top: 0;}
</style>

 

接下来是js代码:

$(function(){
    
 $("#nav li ul.children").hide();
        $("#nav li > ul.children").each(function() {
        $(this).parent("li").hover(function() {
            $(this).children(".children:not(:animated)").animate({opacity: "show", height: "show"}, "slow");
        }, function() {
            $(this).children(".children").animate({opacity: "hide", height: "hide"}, "100");
        });
    });   
 })

 

 js代码很简单。我们又看到老朋友each,这个实例中我们的html代码用了一点小技巧,就是给每一层下拉的ul都设置了相同的class类。

最后效果如图:

jquery下拉菜单全攻略 - 睡觉青蛙 -              sean

 

这个实例是Alan的例子,感谢他的分享。

 

 

 

最后一次趁热打铁我们做一个类似360京东商城首页的下拉菜单效果:效果如图:

posted @ 2013-07-15 17:29  visense  阅读(1082)  评论(1编辑  收藏  举报