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

在这个案例主要用到的知识有:设置定时器,清除定时器,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">
</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:;
margin:;
}
.header{
position: relative;
width: 100%;
height: 50px;
background-color: #000000;
text-align: center;
z-index:;
}
.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:;
width: 100%;
position: relative;
top: -10px;
left:;
background-color: #fff; }
.outerList:hover .link span{
height: 1px;
}
.outerList .inter{
position: absolute;
left:;
height:;
overflow: hidden;
top: 50px;
right:;
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);

用原生JS实现的一个导航下拉菜单,下拉菜单的宽度与浏览器视口的宽度一样(js+html+css)的更多相关文章

  1. bootstrap中container 类和container-fluid类的区别container类所谓的自适应也是通过margin的改变来完成,container-fluid类的百分百宽度是指在固有的15px的padding前提下宽度总是当前视口的宽度。

    container 类和container-fluid类的区别体现在是否有随视口宽度改变的margin存在. container类所谓的自适应也是通过margin的改变来完成,container-fl ...

  2. 使用『jQuery』『原生js』制作一个导航栏动效 —— { }

    效果 HTML部分 <body> <nav> <div id="nav1">导航1</div> <div id="n ...

  3. 原生js写的一个弧形菜单插件

    弧形菜单是一种半弧式或者全弧形菜单,是一种不同于传统横向或者竖向菜单形式的菜单.最近在网上看到好多人写出了这种效果,于是也尝试自己写了一个. 实现方式:原生态js 主要结构: 1.参数合并 var d ...

  4. js获取上一个月、下一个月格式为yyyy-mm-dd的日期

    /** * 获取上一个月 * * @date 格式为yyyy-mm-dd的日期,如:2014-01-25 */ function getPreMonth(date) { var arr = date. ...

  5. gulp插件实现压缩一个文件夹下不同目录下的js文件(支持es6)

    gulp-uglify:压缩js大小,只支持es5 安装: cnpm: cnpm i gulp-uglify -D yarn: yarn add gulp-uglify -D 使用: 代码实现1:压缩 ...

  6. 利用js和JQuery定义一个导航条菜单

    利用js和JQuery定义一个导航条 效果: 一.html代码: <div class="Maintenance"> <div class="Title ...

  7. iOS从当前隐藏导航界面push到下一个显示导航界面出现闪一下的问题

    本文转载至 http://blog.csdn.net/woaifen3344/article/details/41284319 navios 如果有朋友遇到从当前隐藏导航界面push到下一个显示导航界 ...

  8. 用原生js来写一个swiper滑块插件

        是不是有点印象了,没错,他的最基本的用法就是左右滑动,插件使用者只需要写几行简单的html和js即可实现一个简单滑动效果,不过你完全可以组合各种元素来适应不同的场景. 当然插件我已经写好了,咱 ...

  9. 原生JS代码实现一个Ajax异步请求

    异步加载的方式 (1) defer,只支持IE (2) async: (3) 创建script,插入到DOM中,加载完毕后callBack 实现ajax之前必须要创建一个 XMLHttpRequest ...

随机推荐

  1. 2019.3.6 Github学习 &Git学习

    Github学习 1.使用Github 1.1 目的 借助github托管项目代码 1.2 基本概念 仓库(Repository) 仓库的意思是:即你的项目,你想在Github上开源一个项目,那就必须 ...

  2. Kali-linux使用Wifite破解无线网络

    一些破解无线网络程序是使用Aircrack-ng工具集,并添加了一个图形界面或使用文本菜单的形式来破解无线网络.这使得用户使用它们更容易,而且不需要记住任何命令.本节将介绍使用命令行工具Wifite, ...

  3. SpringBoot实战(五)之Thymeleaf

    Thymeleaf同jsp.volocity.freemarker等共同的职能是MVC模式中的视图展示层,即View. 当然了,SpringBoot中也可以用jsp,不过不推荐这种用法,比较推崇的就是 ...

  4. vlc源码分析(六) 调用OpenMAX硬解码H.265

    H.265(HEVC)编码格式能够在得到相同编码质量视频的前提下,使用相当于H.264(AVC)一半的存储容量,虽然H.265的算法复杂度比H.264高一个数量级,但是硬件水平在不断提高,因此H.26 ...

  5. C#中HttpWebRequest的用法详解(转载)

    1.HttpWebRequest和HttpWebResponse类是用于发送和接收HTTP数据的最好选择.2.命名空间:System.Net3.HttpWebRequest对象不是利用new关键字创建 ...

  6. C语言入门编程思维引导

    编程思维引导: C语言中 include<stdio.h>  称之为导包,导入写好的函数库,多个则依次写 #define N 3  意思是将N这个字母定义为数字3 当使用的时候就直接用 i ...

  7. Python入门语法

    Python入门语法 动态变量 a=3  整数 a='abc'   a="abc"    字符串 a=3.0       小数 a=true  a=false   布尔型 a=3  ...

  8. Java 8-接口的默认方法和静态方法

    Java 8-接口的默认方法和静态方法 Java 8使用两个新概念扩展了接口的含义:默认方法和静态方法.默认方法使得接口有点类似traits,不过要实现的目标不一样.默认方法使得开发者可以在 不破坏二 ...

  9. ZooKeeper系列(2)--基于ZooKeeper实现简单的配置中心

    ZooKeeper节点的类型分为以下几类:  1. 持久节点:节点创建后就一直存在,直到有删除操作来主动删除该节点 2. 临时节点:临时节点的生命周期和创建该节点的客户端会话绑定,即如果客户端会话失效 ...

  10. Delphi跨平台下的GetTickCount,GetCurrentThreadID

    在Windows下只要uses Windows,就有这两个API可调用GetTickCount,GetCurrentThreadID 如果我们需要跨平台使用这两个函数,就不能仅仅Uses Window ...