CSS3简单实现动画下拉菜单(display:none和CSS3动画之踩坑)

文本介绍了采用CSS3的 transform 和  transition 属性来实现下拉菜单的动画效果。

由于css3的动画化和display:block以及display:none这两个属性有所冲突,这里提出了一种解决方法。

这里要实现的动画效果是这样的,首先子菜单用display:none来隐藏,它的初始opacity:0,位置向上有一个偏移

当鼠标滑过目标1的时候,子菜单的属性变为为display:block,之后子菜单边出现在下图中虚线处的位置上。接下来,子菜单的opcacity=1,同时下滑。



html代码如下:

这里subBox初始状态处于隐藏状态,因此设置了一个类hide,让其display:none;

			<ul class="menuBox fr">
				<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>博客文章</a>
					<ul class="subBox hide">
						<li><i class="iconfont subNav"></i><a href="#">web前端</a></li>
						<li><i class="iconfont subNav"></i><a href="#">nodejs</a></li>
						<li><i class="iconfont subNav"></i><a href="#">工具用法</a></li>
					</ul>
				</li>
				<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>兴趣分享</a>
					<ul class="subBox hide">
						<li><i class="iconfont subNav"></i><a href="#">书籍</a></li>
						<li><i class="iconfont subNav"></i><a href="#">影视剧</a></li>
						<li><i class="iconfont subNav"></i><a href="#">动漫</a></li>
					</ul>
				</li>
				<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>作品展示</a>
					<ul class="subBox hide">
						<li><i class="iconfont subNav"></i><a href="#">静态仿站</a></li>
						<li><i class="iconfont subNav"></i><a href="#">站点作品</a></li>
						<li><i class="iconfont subNav"></i><a href="#">插件</a></li>
					</ul>
				</li>
				<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>关于本站</a></li>
				<li class="liInMenu"><a href="#" class="aInLi"><i class="iconfont bg nav"></i>关于我</a></li>
			</ul>


liInMenu的css代码如下:

为li设置了relative的定位,以便让subBox基于它定位

.menuBox{
			>li{
				float: left;
				margin-left: 2px;
				position: relative;
}


subBox的css代码如下:

这是subBox的初始状态。

transform:translate3d(0,-50px,0);让其顺着Y轴方向上移。

opacity: 0;让它完全处于透明状态下。

transition:all 0.3s;当subBox要通过css3来实现运动的时候,它所有属性的变化过程都会在持续0.3秒

.subBox{
					border: 1px solid #ddd;
					border-top: none;
					position: absolute;
					z-index: 10;
					left: 0;
					top: 70px;
					width: 100%;
					background-color: #fff;
					opacity: 0;
					-webkit-transform:translate3d(0,-50px,0);
					-moz-transform:translate3d(0,-50px,0);
					-ms-transform:translate3d(0,-50px,0);
					-o-transform:translate3d(0,-50px,0);
					transform:translate3d(0,-50px,0);
					-webkit-transition:all 0.3s;
					-moz-transition:all 0.3s;
					-ms-transition:all 0.3s;
					-o-transition:all 0.3s;
					transition:all 0.3s;
}

鼠标滑过liInMenu时,添加类showBox,代码如下:

				.showBox{
					z-index: 10 !important;
					opacity: 1 !important;
					-webkit-transform:translate3d(0,0,0) !important;
					-moz-transform:translate3d(0,0,0) !important;
					-ms-transform:translate3d(0,0,0) !important;
					-o-transform:translate3d(0,0,0) !important;
					transform:translate3d(0,0,0) !important;
				}


关于JS代码,这里用jquery

最初我打算用事件代理的方式来写,很遗憾,jquery的事件代理不能触发冒泡,而在下拉菜单中必须要用冒泡。

这是原先失败的代码;

	//下拉菜单一定要用到冒泡,由事件代理来实现实在是太麻烦了不可取
	//由于a和li都要触发下拉菜单,不能这样用
	headerMenuBox.on('mouseover',[liInMenuBox,aInLi],function(event){
		console.log('enter')
		var subMenu = 'undefined';
		if ($(event.target).hasClass('liInMenu')) {
			subMenu = $(event.target).children('.subBox')
			console.log(subMenu)
		}
		if ($(event.target).hasClass('aInLi')) {
			var parent = $(event.target).parent('.liInMenu')
			subMenu = parent.children('.subBox')
			console.log(subMenu)
		}
		if (subMenu!=='undefined') {
			subMenu.show().addClass('showMenu')
		}
	})

之后采用了hover来实现,下面我最初的代码

由于需要确定顺序,当移除hide之后再调用函数添加showBox类,确保动画执行。因此用requestAnimationFrame()方法将传入的函数推到下个轮询中调用。

但这里又出现问题了,当我在liInMenu中迅速来回切换的时候,下拉菜单不再显示。

仔细想了想,应该是requestAnimationFrame()的问题,当我从一个liInMenu迅速移动到另一个liInMenu上时,触发了hover的第二个函数,但这时subBox第二个liInMenu的子菜单了,因而没有正确移除目标类。

	var subBox = 'undefined'
	for (var j = 0; j < liInMenuBox.length; j++) {
		liInMenuBox.eq(j).hover(function(event) {
			/* Stuff to do when the mouse enters the element */
			subBox = $(this).children('.subBox')
			subBox.removeClass('hide')
			requestAnimationFrame(function(){
				subBox.addClass('showBox')
			})
		}, function() {
			/* Stuff to do when the mouse leaves the element */
			subBox.removeClass('showBox')//有0.3秒,没有起到作用
			requestAnimationFrame(function(){
				subBox.addClass('hide')
			})

		})
	}
查明原因后,将获取的每个subBox分别单独赋予liInBox的一个属性上,消除了bug,修改的代码如下。

	for (var j = 0; j < liInMenuBox.length; j++) {
		liInMenuBox.eq(j).hover(function(event) {
			/* Stuff to do when the mouse enters the element */
			this.subBox = $(this).children('.subBox')
			this.subBox.removeClass('hide')
			var self = this
			requestAnimationFrame(function(){
				self.subBox.addClass('showBox')
			})
		}, function() {
			/* Stuff to do when the mouse leaves the element */
			this.subBox.removeClass('showBox')//有0.3秒,没有起到作用
			var self = this
			requestAnimationFrame(function(){
				self.subBox.addClass('hide')
			})
			//如果用下面的代码还是会出现问题
			// setTimeout(function(){
			// 	self.subBox.addClass('hide')
			// },350)
		})
	}
但在从liInBox上移除时,上移的效果没有了,这是因为上移的动作持续了30ms,而requestAnimationFrame()推到下个轮询的间隔估计在30ms以内。

不过这个效果也不错,就没有再修改了。

后续如果解决这个bug我再来更新这片文章。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值