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

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

在这个案例主要用到的知识有:设置定时器,清除定时器,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: 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);

时间: 2024-10-04 16:40:28

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

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

弧形菜单是一种半弧式或者全弧形菜单,是一种不同于传统横向或者竖向菜单形式的菜单.最近在网上看到好多人写出了这种效果,于是也尝试自己写了一个. 实现方式:原生态js 主要结构: 1.参数合并 1 var defaultPra = { 2 mainMenuId: "ArcMenu",//主菜单id 3 menuBoxId:"menuBox",//菜单包裹id 4 position: "",//弧形菜单 5 customPosition:"0

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

本文转载至 http://blog.csdn.net/woaifen3344/article/details/41284319 navios 如果有朋友遇到从当前隐藏导航界面push到下一个显示导航界面出现闪一下的问题, 下面是我写的一种方案,也就是在loadView这个生命周期函数中调用一个显示导航条,就 可以解决这个问题: [objc] view plaincopyprint? - (void)loadView { [super loadView]; [self.navigationCont

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

gulp-uglify:压缩js大小,只支持es5 安装: cnpm: cnpm i gulp-uglify -D yarn: yarn add gulp-uglify -D 使用: 代码实现1:压缩js文件夹下的index.js文件输出到dist文件夹下面(注意要压缩的js文件中此处只能使用es5) 1 var gulp = require('gulp'); 2 var uglify = require('gulp-uglify'); 3 4 gulp.task("uglify",f

什么情况下使用break关键字? 什么情况下使用Continue关键字? Java如何声明一个数组?JS如何声明一个数组?如何获取数组长度? 如何遍历数组?

什么情况下使用break关键字?什么情况下使用Continue关键字? Break Break关键用于终止循环. 示例: 1 2 3 4 5 6 for (int i = 0; i < 10; i++) {   if (i == 4) {     break; //终止循环,后面的循环不再执行   }   System.out.println(i); } Continue Continue关键字用于终止本次循环,其它循环继续. 示例: 1 2 3 4 5 6 7 for (int i = 0;

请用原生JS代码实现一个Ajax异步请求。

实现ajax之前必须要创建一个 XMLHttpRequest 对象.如果不支持创建该对象的浏览器,则需要创建 ActiveXObject. var xmlHttp; function createxmlHttpRequest() { if (window.ActiveXObject) { xmlHttp = new ActiveXObject("Microsoft.XMLHTTP"); } else if (window.XMLHttpRequest) { xmlHttp=new XM

.Net MVC&amp;&amp;datatables.js&amp;&amp;bootstrap做一个界面的CRUD有多简单

我们在项目开发中,做得最多的可能就是CRUD,那么我们如何在ASP.NET MVC中来做CRUD呢?如果说只是单纯实现功能,那自然是再简单不过了,可是我们要考虑如何来做得比较好维护比较好扩展,如何做得比较漂亮.做开发要有工匠精神,不要只求完成开发任务,那样的话,永远停留在只是简单的写业务逻辑代码水平,我们要做有追求的程序员.本来这么简单的东西,我真是懒得写,但是看到即便是一些工作了好些年的人,做东西也是只管实现功能,啥都不管,还有些界面css样式要么就硬编要么就毫无规则的在页面中进行穿插,遇到要

[应用][js+css3]3D盒子导航[PC端]

CSS3构建的3D盒子之导航应用 1.在用css3构建的盒子表面,放上iframe,来加载导航页面. 2.鼠标左键按下移动可旋转盒子,寻找想要的网址. 3.左键单机盒子表面,将全屏现实所点盒子表面的网站[iframe中],并可浏览,关闭后返回原来状态. 4.PC端,将额外显示2个css3做的旋转盒子[没什么意义] 5.移动端只显示一个导航盒子[模拟器正常,真机无效,留待以后查看,兼容开发有待提高...] 注:原本打算排列导航盒子,这样的话导航也变得比较好玩 但是,如果使用iframe来显示网站预

JS 学习制作一个二级菜单

1 <!DOCTYPE html> 2 <html xmlns="http://www.w3.org/1999/xhtml"> 3 <head> 4 <title>菜单栏</title> 5 <script src="jquery/jquery-2.1.1.js"></script> 6 <script> 7 $(document).ready(function () {

用Vue.js来开发一个电影App的前端部分

我们要构建一个什么样的App? 我们大多数人使用在线流媒体服务(如Netflix)观看我们最喜欢的电影或者节目.这篇文章将重点介绍如何通过使用vue.js 2建立一个类似风格的电影流媒体WEB交互界面(见上图). 最终的产品可以去这里找:https://codepen.io/itslit/full/mvvjzr. 尽管Bulma将作为应用的CSS框架,但是本文将主要集中在Vue.js的使用和浏览CSS式样,如果你想跟着学,我设置了一个可以作为开始学习的地方,所有自定义组合,初始数据对象和必要的需