注:该练习中涉及的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源码:
<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="#">CodingForumsa>
<a href="#">CSS例子a>
div>
<div class="collapsed">
<span class="menuSpan">测试电流span>
<a href="#">Current or nota>
<a href="#">Current or nota>
<a href="#">Current or nota>
<a href="#">Current or nota>
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);
}
}
希望本练习对你有所帮助,加油!