js通过类的改变实现二级菜单过渡效果

通过点击菜单显示或折叠菜单

使用添加删除某个类的样式来实现

<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8">
		<title>二级菜单</title>
		<script src="../js/tools.js" type="text/javascript" charset="utf-8"></script>
		<style type="text/css">
			*{margin: 0;padding: 0;}
			#box{
				margin: 50px auto;
				width: 200px;
			}
			.inner{
				height: 30px;
				overflow: hidden;
			}
			li{
				list-style: none;
				height: 30px;
				width: 200px;
				line-height: 30px;
				background: #A6F188;
			}
			span{
				display: block;
				width: 200px;
				height: 30px;
				line-height: 30px;
				background: #FFC0CB;
			}
			/* 展开 */
			.unfold{
				height: 120px;
				overflow: block;
			}
			
		</style>
	</head>
	
	<body>
		<div id="box">
			<div class="inner unfold">
				<span>音乐</span>
				<ul>
					<li>曾经的你</li>
					<li>七月上</li>
					<li>不露声色</li>
				</ul>
			</div>
			<div class="inner">
				<span>电影</span>
				<ul>
					<li>南方车站的聚会</li>
					<li>被嫌弃的松子的一生</li>
					<li>悲伤逆流成河</li>
				</ul>
			</div>
			<div class="inner">
				<span>love</span>
				<ul>
					<li>胡歌</li>
					<li>jia</li>
					<li>guo</li>
				</ul>
			</div>
		</div>
		<script type="text/javascript">
			var oSpan = document.querySelectorAll("span");
			var oIndex = oSpan[0].parentNode;
			for(var i = 0; i < oSpan.length; i++){
				oSpan[i].onclick = function(){
					var oDiv = this.parentNode;
					//对象切换,并具有过渡效果
					guodu(oDiv);
					//这个和下面代码效果一样,只是为了方便使用过渡函数
					if(oIndex != oDiv && hasClass(oIndex,"unfold")){
						//changeStyle(oIndex,"unfold");
						guodu(oIndex);
					}
					/* if(oIndex != oDiv ){
						removeClass(oIndex,"unfold");
					} */
					oIndex = oDiv;
				}
			}
			//实现二级菜单的过渡效果,菜单展开,菜单折叠时具有过渡效果
			function guodu(obj){
				//先获取切换前的值
				var begin = obj.offsetHeight;
				changeStyle(obj,"unfold");//切换
				var target = obj.offsetHeight; //获取切换后的值
				//再将它设置为切换前的值,相当于没有发生变化,单纯的想要获取切换以后的值
				obj.style.height = begin+"px"; 
				//将目标值传入封装函数,改变对象的某个属性,实现过渡效果
				startMove(obj,{"height":target},function(){
					obj.style.height = "";
				});
			}
			
		</script>
	</body>
</html>

tools.js中封装的函数

//传入对象,以及为它添加的类名,可以将这个对象添加上这个类名的样式
function changeStyle(domobj,cName){
	if(hasClass(domobj,cName)){
		removeClass(domobj,cName);
	}else{
		addClass(domobj,cName);
	}
}
function hasClass(domobj,cName){
	var reg = new RegExp("\\b"+cName+"\\b");
	if(reg.test(domobj.className)){
		return true;
	}else{
		return false;
	}
	
}
function addClass(domobj,cName){
	domobj.className += " "+cName;
}
function removeClass(domobj,cName){
	domobj.className = domobj.className.replace(cName,"");
}

//一个对象的css样式发生变化,json传入要变化的属性和目标值
function startMove(domobj,json,fn){
	//每一个对象只有一个定时器,防止对同一个对象调用多次定时器,所以在对某个对象调用定时器时
	//先清除它之前的定时器
	
	clearInterval(domobj.timer);
	domobj.timer = setInterval(()=>{
		var flag = true;//为检测属性是否全部执行完,先假设全部执行完,最后再测试,只要有一个
		//没有执行完,就设为false,不能清除定时器
		for(let attr in json){
			var target = json[attr];
			var current= parseInt(getStyle(domobj,attr));
			//专门检测是否有透明度的变化,因为它的值为小数,所以避免舍入进位时出错,特殊处理
			if(attr == "opacity"){
				current = getStyle(domobj,attr)*100;
			}
			var speed = (target-current)/7;
			//为达到减速的效果,将每次未走完的长度均分,每次走剩下的几分之一,这样在相同时间内
			//走的越来越少,也就达到了减速效果,但这样也产生了一个问题,就是永远走剩下的几分之一,
			//永远到不了目标值,所以采用math.ceil和math.floor的方法,分别对应当前值小于目标值,
			//当前值大于目标值的时候,这样就可以达到目标值
			speed = speed>0?Math.ceil(speed):Math.floor(speed);
			if(attr == "opacity"){
				domobj.style.opacity = (current+speed)/100;
				domobj.style.filter="alpha(opacity:("+(current+speed)+")";
			}else{
				domobj.style[attr] = current+speed+"px";
			}
			//如果同时变化的属性有没有执行完的,则不会执行清除定时器的操作
			if(current != target){
				flag = false;
			}	
		}
		if(flag){
			clearInterval(domobj.timer);
			//第一次要同时变化的属性全部变化完,则执行回调函数,会执行第二次要变化的属性
			if(fn){
				fn();
			}
		}
	},30)
}
//获取内联或外联的样式值的兼容写法的封装函数
function getStyle(domobj,attr){
	if(window.getComputedStyle){
		return getComputedStyle(domobj,null)[attr];
	}
	return domobj.currentStyle[attr];
}
			

 

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值