原生JS实现导航下拉菜单效果

这个导航下拉菜单需要实现的功能是:下拉菜单的宽度与浏览器视口的宽度一样宽;一级导航只有两项,当鼠标移到一级导航上的导航项时,相应的二级导航出现。在本案例中通过改变二级导航的高度来实现二级导航的显示和消失。为了便于理解我画了一个图,如下:

原生JS实现导航下拉菜单效果

在这个案例主要用到的知识有:设置定时器,清除定时器,mouseout和mouseover事件,另外还有css中position相关知识。本案例分为两部分讲解。第一部分html和css,第二部分js。

一. html和css

将导航这个导航条包裹在一个div中,这个div的position值为relative,高度为50px(导航条的高度为50px),宽度为100%,将最外层的div的position属性设置为relative是因为二级导航要根据这个div来定位。这个导航条的结构是二级嵌套无序列表。每一个一级导航项li都嵌套了它对应的无序列表。需要将嵌套的无序列表移除文档流。所以嵌套的无序列表的position值为absolute,top:50px(导航条的高度)。left:0;right:0;通过设置这些值可以使嵌套的无序列表宽度为浏览器视口的宽度。通过将li的display值设置inline-block并且将外层div的text-align设置为center使得导航项居中显示。

注:在这个案例中一定要将嵌套的无序列表的position的值设置为absolute,使它移除文档流。

html和css代码如下:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>下拉菜单</title>
  <link rel="stylesheet" type="text/css" href="index.css" rel="external nofollow" >
</head>
<body>
  <div class='header'>
    <ul class='outer' id='outer'>
      <li class='outerList' id='outerList1'><a href='#' id='link1' class='link'>产品<span></span></a>
        <ul class='inter' id='inter1'>
          <li>
            <a href='#'>
              <img src='img/01fea55541ed73000001714a430253.jpg'>
              <strong>纳斯</strong>
            </a>
          </li>
          <li>
            <a href='#'>
              <img src='img/thumb_image3.jpg'>
              <strong>纯色</strong>
            </a>
          </li>
          <li>
            <a href='#'>
              <img src='img/白胡子.jpg'>
              <strong>保温杯</strong>
            </a>
          </li>
          <li>
            <a href='#'>
              <img src='img/宠物.jpg'>
              <strong>设计周边</strong>
            </a>
          </li>
        </ul>
      </li>
      <li class='outerList' id='outerList2'><a href='#' id='link2' class='link'>服务<span></span></a>
        <ul class='inter' id = 'inter2'>
          <li>
            <a href='#'>
              <img src='img/狮子座.jpg'>
              <strong>售后服务</strong>
            </a>
          </li>
          <li>
            <a href='#'>
              <img src='img/莲花禅.jpg'>
              <strong>设计师</strong>
            </a>
          </li>
        </ul>
      </li>
    </ul>
  </div>
  <script type="text/javascript" src='index.js'></script>
</body>
</html>

css代码如下:

*{
  padding: 0;
  margin: 0;
}
.header{
  position: relative;
  width: 100%;
  height: 50px;
  background-color: #000000;
  text-align: center;
  z-index: 2;
}
.header .outer li{
  display: inline-block;
  list-style: none;
}
.outerList{
  height: 50px;
  line-height: 50px;

}
.outerList a{
  display: block;
  padding: 0 15px;
  color: #fff;
  text-decoration: none;
}
.outerList:hover a{
  color: #EDECEC;

}
.outerList .link span{
  display: block;
  height: 0;
  width: 100%;
  position: relative;
  top: -10px;
  left: 0;
  background-color: #fff;

}
.outerList:hover .link span{
  height: 1px;
}
.outerList .inter{
  position: absolute;
  left: 0;
  height: 0;
  overflow: hidden;
  top: 50px;
  right: 0;
  background-color:rgba(0,0,0,0.5);
}
.outerList .inter li{
  margin-top: 30px;
}
.outerList .inter strong{
  display:block;
  height: 25px;
  line-height: 25px;
  text-align: center;
}

二. js部分

在js部分涉及到的知识主要有:设置定时器,清除定时器,mouseout和mouseover事件。

mouseout事件当鼠标从一个元素上移入另一个元素的上时,会在失去鼠标的那个元素上触发mouseout事件。获得鼠标的那个元素可能是失去鼠标的元素的父元素或子元素,获得鼠标的那个元素也可能位于失去鼠标元素的外部。当在一级导航项上触发mouseout事件时,我们需要判断获得鼠标的元素是不是一级导航项的子孙元素。当一个元素触发了mouseout事件时,去鼠标的元素为目标元素(target),获得鼠标的元素为相关元素(relatedTarget)。所以需要判断相关元素是否为一级导航项的子孙元素,如果是子孙元素,则相应的导航项的二级导航项高度不变。如果不是子孙元素,则相应的二级导航项消失。判断是否为子孙元素的代码如下:

var flag1 = false,flag2 = false;

if(relatedTarget !== null){
    var parented = relatedTarget.parentNode;
    do{
      if(parented === outerList1 || relatedTarget === outerList1){
        flag1 = true;
        break;
      }else if(parented === outerList2 || relatedTarget === outerList2){
        flag2 = true;
        break;
      }else{
        parented = parented.parentNode;
      }
    }while(parented !== null);
  }

注:通过判断flag1和flag2的值来确定是否该把二级菜单的高度变为0,如果flag1的值为false则让outerList1对应的二级菜单消失,如果flag2为false则将outerList2对应的二级菜单消失。

mouseover事件当鼠标移入一个元素内部时,获得鼠标的元素上触发这个事件,获得鼠标的元素可能位于失去鼠标的外部,也可能位于失去鼠标元素的内部。获得鼠标的元素是目标元素,失去鼠标的元素为相关元素。在这个案例中我们只需要判断mouseover的目标元素,但是对于mouseout事件我们需要判断相关元素。

注:在支持DOM的浏览器中,mouseout和mouseover的相关元素都保存在事件对象(event)的relatedTagrget属性中,但是在IE浏览器中,对于mouseout事件而言,相关事件保持在事件对象(event)的toElement属性中,对于mouseover事件而言,相关事件保存在事件对象(event)的fromElement属性中。

设置定时器和清除定时器在这个案例中嵌套无序列表的消失和出现是通过改变它的高度实现的,它的高度是逐渐变化,所以我使用的setTimeout这个定时器,为了能够清除定时器还要将定时器标识保存在一个变量中。清除定时器的目的是为了防止当快速移动鼠标时嵌套无序列表的高度抖动(即:一个定时器里的回调函数让高度增加,另一个定时器的回调函数让高度减小)。

js代码如下:

var untilEvent = {
  addEvent:function(element,type,hander){
    if(element.addEventListener){
      element.addEventListener(type,hander,false);
    }else if(element.attachEvent){
      element.attachEvent('on'+type,hander);
    }else{
      element['on'+type] = hander;
    }
  },
  getEvent:function(event){
    return event?event:window.event;
  },
  getTarget:function(event){
    return event.target||event.srcElement;
  },
  getRelated:function(event){
    if(event.relatedTarget){
      //兼容DOM的浏览器将相关元素保持在relatedTarget属性中
      return event.relatedTarget;
    }else if(event.toElement){
      //在IE浏览器中mouseout事件的相关元素保存在toElement属性中
      return event.toElement;
    }else if(event.fromElement){
      //在IE浏览器中mouseover事件的相关元素保持在fromElement属性中
      return event.fromElement;
    }else{
      return null;
    }
  }

};
//下面这四个元素用于表示四个定时器的标识,最开始我只使用两个定时器,当快速移动时
//动画会乱。
var timeDec1,timeAdd1,timeAdd2,timeDec2;//定时器标识
function getOuter(){
  var outer = document.getElementById('outer');
  untilEvent.addEvent(outer,'mouseover',callBackOver);
  untilEvent.addEvent(outer,'mouseout',callBackOut);
}
//mouseout事件:当鼠标从一个元素移入另一个元素时在鼠标离开的那个元素
//上触发,获得鼠标的元素可能在失去鼠标元素的外部也可能在失去鼠标元素的
//内部.所以需要判断mouseout事件的相关元素是否为外部li(即id为outerList或id为outerList2)元素
//的子孙元素,如果是子孙元素,则内部无序列表无须收起。
function callBackOut(event){
  var event = untilEvent.getEvent(event);
  var relatedTarget = untilEvent.getRelated(event);
  var outerList1 = document.getElementById('outerList1');
  var inter1 = document.getElementById('inter1');
  var outerList2 = document.getElementById('outerList2');
  var inter2 = document.getElementById('inter2');
  var flag1 = false,flag2 = false;
  if(relatedTarget !== null){
    var parented = relatedTarget.parentNode;
    do{
      if(parented === outerList1 || relatedTarget === outerList1){
        flag1 = true;
        break;
      }else if(parented === outerList2 || relatedTarget === outerList2){
        flag2 = true;
        break;
      }else{
        parented = parented.parentNode;
      }
    }while(parented !== null);
  }
  if(!flag1){
    var str1 = 'flag1';
    changeHeightDec(inter1,timeAdd1,str1);
  }
  if(!flag2){
    var str2 = 'flag2';
    changeHeightDec(inter2,timeAdd2,str2);
  }
}
function changeHeightDec(element,timer,flag){
  var offHeight = 70;
  var inverTimer = 10;
  clearTimeout(timer);
  change();
  function change(){
    var height = parseInt(element.style.height);
    if(!height)height = 0;
    if(height > 0){
      if(height - offHeight > 0){
      element.style.height = height - offHeight +'px';
      }else{
        element.style.height = 0+'px';
      }
      if(flag === 'flag1'){
       timeDec1= setTimeout(change,inverTimer);
      }else{
        timeDec2 = setTimeout(change,inverTimer);
      }
    }
  }
}
function callBackOver(event){
  var event = untilEvent.getEvent(event);
  var target = untilEvent.getTarget(event);
  var inter1 = document.getElementById('inter1');
  var inter2 = document.getElementById('inter2');
  if(target.id == 'outerList1' || target.id == "link1"){
    var str1 = "flag1";
    changeHeight(inter1,timeDec1,str1);
  }
  if(target.id == 'outerList2' || target.id == 'link2'){
    var str2 = "flag2";
    changeHeight(inter2,timeDec2,str2);
  }
}
function changeHeight(element,timer,flag){
  var totalHeight = 160;
  var inverHeight = 10;
  var inverTimer = 10;
  clearTimeout(timer);
  //当鼠标移入时清除让内部ul长度减小的定时器,保证鼠标移入后
  //内部ul长度立即增加
  change();
  function change(){
    var height = parseInt(element.style.height);
    if(!height) height = 0;
    if(height < totalHeight){
      if(height + inverHeight > totalHeight){
        element.style.height = totalHeight + "px";
      }else{
        element.style.height = height + inverHeight +'px';
      }
      if(flag === 'flag1'){
        timeAdd1 = setTimeout(change,inverTimer);
        }else{
          timeAdd2 = setTimeout(change,inverTimer);
        }
    }
  }
}
untilEvent.addEvent(window,'load',getOuter);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

时间: 2017-03-21

jquery实现简单的二级导航下拉菜单效果

本文实例讲述了jquery实现简单的二级导航下拉菜单效果.分享给大家供大家参考.具体如下: jQuery代码实现的二级导航菜单效果,非常简洁,喜欢简洁风格的朋友您可以下载哦.菜单最多支持两级,CSS的配合也是挺重要的,不多说了,要代码的就直接复制吧. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-2jxl-menu-codes/ 具体代码如下: <title>jquery二级导航菜单</title> <styl

jQuery实现的简洁下拉菜单导航效果代码

本文实例讲述了jQuery实现的简洁下拉菜单导航效果.分享给大家供大家参考.具体如下: 这里使用jQuery实现简洁下拉菜单导航效果,代码规范,兼容性方面:支持 IE6+, Firefox 1.5+, Opera 8+, Safari 3+, Chrome 0.2+.简洁明快的jquery网站菜单,请参阅代码. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/jquery-simple-down-show-menu-nav-codes/ 具体代码

JS中用三种方式实现导航菜单中的二级下拉菜单

我们在淘宝.搜狐等大型网站上都可以看到使用的一些二级下拉菜单,比如下面这张图片.那么如何实现导航菜单栏中的二级下拉菜单?下面小编给大家分享实现思路. 但是如何实现类似的图片呢?实际上,我们有至少三种方式来实现,下面,我附上代码供大家参考. 1.仅使用html和css <meta charset="UTF-8"> <title>Document</title> <style> *{margin:0;padding: 0;list-style

顶部缓冲下拉菜单导航特效的JS代码

复制代码 代码如下: <script type="text/javascript">            $(function() {                var d=300;                $('#navigation a').each(function(){                    $(this).stop().animate({                        'marginTop':'-80px'       

JS 实现导航菜单中的二级下拉菜单的几种方式

最近整理了, JS 实现导航菜单中的二级下拉菜单的三种方式,便于项目中应用. 如何实现导航菜单栏中的二级下拉菜单? 我们在淘宝.搜狐等大型网站上都可以看到使用的一些二级下拉菜单,比如下面这张图片. 但是如何实现类似的图片呢?实际上,我们有至少三种方式来实现,下面,我附上代码供大家参考. 1.仅使用html和css <meta charset="UTF-8"> <title>Document</title> <style> *{margin

js实现兼容性好的微软官网导航下拉菜单效果

本文实例讲述了js实现兼容性好的微软官网导航下拉菜单效果.分享给大家供大家参考.具体如下: 这是一款微软官网导航菜单,兼容好的下拉菜单,微软官网导航效果,在IE6下没有动画效果,顺便也把IE6的效果给加上,兼容IE6.现在微软的官方网站正在使用,我觉得非常不错. 运行效果截图如下: 在线演示地址如下: http://demo.jb51.net/js/2015/js-microsoft-web-nav-menu-codes/ 具体代码如下: <!DOCTYPE html PUBLIC "-/

基于JS快速实现导航下拉菜单动画效果附源码下载

这是一个带变形动画特效的下拉导航菜单特效.该导航菜单在菜单项之间切换时,下拉菜单会快速的根据菜单内容的大小来动态变形,显示合适的下拉菜单大小,效果非常棒. 快速的导航下拉菜单动画效果如下所示: 效果演示         源码下载 HTML 该导航菜单的HTML结构如下: <header class="cd-morph-dropdown"> <a href="#0" class="nav-trigger">Open Nav&

jquery仿京东导航/仿淘宝商城左侧分类导航下拉菜单效果

在网站建设中,特别是做商城和产品网站,通常会用到导航弹出菜单,像是jquery写的仿京东导航菜单,一个经典的左侧多级导航菜单,学会了可以任意改变布局.京东菜单已经有不少JS前端爱好者仿写过,今天蚂蚁网络重新与大家分享一款仿京东商城的商品多级分类菜单,精简版代码 先看下jquery仿京东导航效果: 前端html代码如下: 复制代码 代码如下: <ul> <li><a href="#">baidu</a></li> <div

javascript仿京东导航左侧分类导航下拉菜单效果

本文实例为大家分享了类似于京东.淘宝商城左侧分类导航下拉菜单,供大家参考,具体内容如下 效果图: 实现代码: <!DOCTYPE html> <html> <head> <meta charset="gb2312"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <title></title> <

JS实现快速的导航下拉菜单动画效果附源码下载

这是一个带变形动画特效的下拉导航菜单特效.该导航菜单在菜单项之间切换时,下拉菜单会快速的根据菜单内容的大小来动态变形,显示合适的下拉菜单大小,效果非常棒. 查看演示     下载源码 HTML 该导航菜单的HTML结构如下: <header class="cd-morph-dropdown"> <a href="#0" class="nav-trigger">Open Nav<span aria-hidden=&qu

基于jQuery实现鼠标点击导航菜单水波动画效果附源码下载

基于jQuery鼠标点击水波动画竖直导航代码.这是一款基于jQuery+CSS3实现的带动画效果的竖直导航栏特效.效果图如下: 效果展示    源码下载 html代码: <div class="nav"> <ul> <li><a>网站首页</a></li> <li><a>关于我们</a></li> <li><a>产品中心</a>&l

基于jQuery实现select下拉选择可输入附源码下载

我们知道,一般select下拉框是只能选择的,不能用来输入内容的.而有时我们会遇到下拉框中没有要选择的信息项或者下拉选项特别多时,我们可以让select变成text,允许用户输入想要的内容,同时还可以在输入的时候将包含关键字的项也列出来,供快速选择. 查看演示效果           源码下载 本文将用实例和大家分享一款基于jQuery的下拉框插件,它允许用户输入内容,同时下拉选项中会及时匹配相关选项,支持键盘操作,还支持html选项内容,当然还能让下拉的过程带有动画效果.我们来看下如何使用.

jQuery插件ImageDrawer.js实现动态绘制图片动画(附源码下载)

ImageDrawer.js是一款可以实现动态绘制图片动画的jQuery插件.通过ImageDrawer.js插件,你可以制作在页面中绘制图片的动态过程,你可以控制绘制动画的持续时间等参数,非常有趣. 效果展示       源码下载 使用方法 使用该动态绘制图片插件需要在页面中引入imagedrawer.css,jquery和imagedrawer.js文件. <link rel="stylesheet" href="css/imagedrawer.css"

avalon js实现仿google plus图片多张拖动排序附源码下载

源码下载:http://xiazai.jb51.net/201509/yuanma/drag_sort1(jb51.net).rar 效果展示如下: google plus 拖动+响应式效果: 要求 1. 两边对齐布局,即图片间间距一致,但左右两边的图片与边界的间距不一定等于图片间间距,兼容ie7,8,firefox,chrome. 2. 浏览器尺寸变化,在大于一定尺寸时,每行自动增加或减少图片,自动调整图片间间距,以满足两边对齐布局,这时每张图片尺寸固定(这里是200*200px):而小于一定

JS实现移动端按首字母检索城市列表附源码下载

我们常见的手机通讯录或微信通讯录,联系人信息是按字母顺序排列的列表,通过点击右侧的字母,会迅速定位检索到首字母对应的联系人.那么我今天给大家介绍的是按首字母快速定位到城市列表,效果和通讯录一样的.  查看演示 下载源码 准备 查看演示     下载源码 准备 首先我们需要用到全国的城市数据,这些城市数据来源于网络,我已经将数据格式化成JSON形式了,大家可以直接拿去用. 我们还需要用到一个叫better-scroll的滚动插件,它能帮我们将超长的页面原生的滚动条处理掉,优化滚动效果. 接着我们准