HTML/CSS/JS制作网页中的二级下拉菜单

37 篇文章 8 订阅
30 篇文章 0 订阅

注:该练习中涉及的move方法(移动效果)可参考博文“JavaScript_网页中使用按钮控制图形的移动效果(https://editor.csdn.net/md/?articleId=115607200)”

若对此练习有所疑惑可参考尚硅谷李立超老师在B站的js基础教程(https://www.bilibili.com/video/BV1YW411T7GX?p=138)

下面我们看一下该下拉菜单的效果图:
在这里插入图片描述
以下为源码和解析:
css文件:second.css

@charset "utf-8";

/* sdmenu */

div.sdmenu {
	width: 150px;
	margin: 100px auto;
	font-family: Arial, sans-serif;
	font-size: 12px;
    padding-bottom: 10px;
    background: url(bottom.gif) no-repeat right bottom;
    color: #fff;
}

div.sdmenu div {
    background: url(title.gif) repeat-x;
    overflow: hidden;
}

div.sdmenu div:first-child{
    background: url(toptitle.gif) no-repeat;
}

div.sdmenu div.collapsed{
    height: 25px;
}

div.sdmenu div span{
    display: block;
    height: 15px;
    overflow: hidden;
    padding: 5px 25px;
    font-weight: bold;
    color: white;
    background: url(expanded.gif) no-repeat 10px center;
    cursor: pointer;
    border-bottom: 1px solid #ddd;
}

div.sdmenu div.collapsed span{
    background-image: url(collapsed.gif);
}

div.sdmenu div a{
    padding: 5px 10px;
    background: #eee;
    display: block;
    border-bottom: 1px solid #ddd;
    color: #066;
}

div.sdmenu div a.current{
    background: #ccc;
}

div.sdmenu div a:hover{
    background: #066 url(linkarrow.gif) no-repeat right center;
    color: #fff;
    text-decoration: none;
}

html及JS源码:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>二级菜单</title>
        <link rel="stylesheet" href="css/second.css">
        <style>
            *{
                padding: 0px;
                margin: 0px;
                list-style-type: none;
            }
            a,img{
                border: 0px;
                text-decoration: none;
            }
            body{
                font: 12px/180%;
            }
        </style>
        <script src="./js/tools.js"></script>
        <script>
            window.onload = function(){
                /* 
                    我们的每一个菜单都是一个div
                        当div具有collapsed这个类时,div就是折叠状态
                        当div没有这个类时,div就是展开状态
                        
                    点击菜单,切换菜单的显示状态
                 */

                 //获取所有的class为menuSpan的元素
                var menuSpan = document.querySelectorAll(".menuSpan");

                console.log(menuSpan.length);    
                
                //定义一个变量,保存当前打开的菜单
                var openDiv = menuSpan[0].parentNode;

                //绑定span单击响应函数
                for(var i=0; i<menuSpan.length; i++){
                    menuSpan[i].onclick = function(){
                        //this代表当前点击的span
                        //获取当前span的父元素
                        var  parentDiv = this.parentNode;

                        toggleMenu(parentDiv);

                        //判断openDiv和parentDiv是否相同
                        if(openDiv != parentDiv && !hasClass(openDiv, "collapsed")){
                            //打开菜单以后,应该关闭之前打开的菜单
                            //为了可以统一处理动画过渡效果,我们希望将addClass改为toggleClass;
                            // addClass(openDiv, "collapsed");
                            // 此处toggleClass()不需要有移除功能
                            // toggleClass(openDiv, "collapsed");
                            
                            //切换菜单的显示状态
                            toggleMenu(openDiv);
                        }
                        //修改openDiv 为当前打开的菜单
                        openDiv = parentDiv;

                    };
                }

                //切换菜单的折叠和显示状态
                function toggleMenu(obj){
                    var begin = obj.offsetHeight;

                        //切换parentDiv的显示
                        toggleClass(obj, "collapsed");

                        //在切换类之后,获取一个高度
                        var end = obj.offsetHeight;
                        // console.log(begin+ " "+end);
                        // 动画效果就是将高度从begin向end过渡
                        // 将元素的高度重置为begin
                        obj.style.height = begin + "px"
                        // console.log(parentDiv.style.height);
                        // 执行动画,从begin向end过渡
                        move(obj, "height", end, 10, function(){
                            // 动画执行完毕,内联样式已经没有存在的意义,需删除
                            obj.style.height = "";
                        });
                }
            };

            
        </script>
    </head>
    <body>
        <div id="my_menu" class="sdmenu">
			<div>
				<span class="menuSpan">在线工具</span>
				<a href="#">图像优化</a>
				<a href="#">收藏夹图标生成器</a>
				<a href="#">邮件</a>
				<a href="#">htaccess密码</a>
				<a href="#">梯度图像</a>
				<a href="#">按钮生成器</a>
			</div>
			<div class="collapsed">
				<span class="menuSpan">支持我们</span>
				<a href="#">推荐我们</a>
				<a href="#">链接我们</a>
				<a href="#">网络资源</a>
			</div>
			<div class="collapsed">
				<span class="menuSpan">合作伙伴</span>
				<a href="#">JavaScript工具包</a>
				<a href="#">CSS驱动</a>
				<a href="#">CodingForums</a>
				<a href="#">CSS例子</a>
			</div>
			<div class="collapsed">
				<span class="menuSpan">测试电流</span>
				<a href="#">Current or not</a>
				<a href="#">Current or not</a>
				<a href="#">Current or not</a>
				<a href="#">Current or not</a>
			</div>
		</div>
    </body>
</html>

通用的js方法:tool.js
注:该文件中主要包含三方面的方法,即:获取元素属性方法、移动动画方法、增删元素类方法
源码:


//移动效果————move()方法
/* 
            目前我们的定时器的标识由全局变量timer保存
                所有的执行正在执行的定时器都在这个变量中保存
         */

            var timer;
            //创建一个可以执行简单动画的函数
            /* 
                参数:
                     obj:要执行动画的对象
                    st: 要执行动画的样式,比如:left、top、width
                    target: 执行动画的目标位置
                    speed: 移动的速度(正数向右移动,负数向左移动)
                    callback: 回调函数,这个函数将会在动画执行完毕以后执行
             */
            function move(obj, st, target, speed, callback){
                clearInterval(obj.timer);
    
                var current = parseInt(getStyle(obj, st));
                //判断速度的正负值
                //如果从0向400移动,则speed为正
                //如果从400向0移动,则speed为负
                console.log(current + "  " + target);
                if(current > target){
                    speed = -speed;
                }
        
                obj.timer = setInterval(function(){
                    //获取box1的原来的left值
                var oldValue = parseInt(getStyle(obj, st));
                    console.log(oldValue);
                    //在旧值的基础上增加
                    var newValue = oldValue + speed ;
                    //将新值设置给box1
                    obj.style[st] = newValue + "px";    
    
                    if(speed < 0 && newValue <= target){
                        obj.style[st] = target + "px"; 
                        clearInterval(obj.timer);
    
                        //动画执行完毕,调用回调函数
                        callback && callback(); //如果有callback则执行,否则不执行
    
                    }else if(speed > 0 && newValue >= target){
                        obj.style[st] = target + "px";
                        clearInterval(obj.timer);
        
                        //动画执行完毕,调用回调函数
                        callback && callback(); //如果有callback则执行,否则不执行
                    }
                        
                }, 10);
            }


//版本适配后的获取元素属性的方法_getStyle()
function getStyle(obj, name){
    //此处条件不可直接使用getComputedStyle作为参数,因为在浏览器中变量没找到会报错
                // 而作为window的属性使用,属性找不到会返回false,如果是IE8浏览器则会返回false
                //  如果是IE8以上的版本或者其他类型浏览器,则返回true
                if(window.getComputedStyle){
                //正常浏览器的方式,具有getComputedStyle方法
                    return getComputedStyle(obj, null)[name];
                }else{
                    //IE8的方式,没有getComputedStyle方法
                    return obj.currentStyle[name];
                }
        
                //另一种方法
                //该方法有缺陷,因为IE9/10/11即含有currentStyle属性有含有getComputedStyle方法
                // if(obj.currentStyle){
                //     return obj.currentStyle[name];
                // }else{
                //     return obj.getComputedStyle[name];
                // }                
}  


//删除、添加、替换、判断类是否存在  的方法(removeClass、addClass、toggleClass、hasClass)
//定义一个函数,用来向一个元素中添加指定的class属性值
            /* 
                参数:
                    obj  要添加class属性的元素
                    ch   要添加的class值
             */
                    function addClass(obj, cn){
                        console.log(hasClass(obj, cn));
                        if(!hasClass(obj, cn)){
                            obj.className += " " + cn; // 空格不可缺
                        }
                    }
        
                    /* 
                        判断一个元素中是否含有指定的class属性值
                     */
                    function hasClass(obj, cn){
                        //判断obj是否含有cn
                        // if( obj.className.indexOf(" " + cn + " ") > -1){
                        //     console.log(obj.className.indexOf(cn));
                        //     return true;
                        // }else{
                        //     return false;
                        // }
                        
                        //创建一个正则表达式
                        var reg = new RegExp("\\b" + cn + "\\b");
                        console.log(reg);
                        return reg.test(obj.className);
                    }
                    //删除指定类
                    function removeClass(obj, cn){
                        var reg = new RegExp("\\b"+ cn +"\\b");
                        obj.className = obj.className.replace(reg, "");
                    }
                    /* 
                        toggleClass可以用来切换一个类
                        如果元素中具有该类,则删除
                        如果元素中没有该类,则添加
                     */
                    function toggleClass(obj, cn){
                        if(hasClass(obj, cn)){
                            removeClass(obj, cn);
                        }else{
                            addClass(obj, cn);
                        }
                    }

希望本练习对你有所帮助,加油!

  • 5
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值