用原生JS實現的一個導航下拉菜單,下拉菜單的寬度與瀏覽器視口的寬度同樣(js+html+css)

這個導航下拉菜單須要實現的功能是:下拉菜單的寬度與瀏覽器視口的寬度同樣寬;一級導航只有兩項,當鼠標移到一級導航上的導航項時,相應的二級導航出現。在本案例中經過改變二級導航的高度來實現二級導航的顯示和消失。爲了便於理解我畫了一個圖,以下:javascript

在這個案例主要用到的知識有:設置定時器,清除定時器,mouseout和mouseover事件,另外還有css中position相關知識。本案例分爲兩部分講解。第一部分html和css,第二部分js。css

一. 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使得導航項居中顯示。html

注:在這個案例中必定要將嵌套的無序列表的position的值設置爲absolute,使它移除文檔流。java

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)。因此須要判斷相關元素是否爲一級導航項的子孫元素,若是是子孫元素,則相應的導航項的二級導航項高度不變。若是不是子孫元素,則相應的二級導航項消失。判斷是否爲子孫元素的代碼以下:spa

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事件咱們須要判斷相關元素。code

注:在支持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);
相關文章
相關標籤/搜索