<!-- jquery 移除事件,绑定一次事件,搜狗 one --> <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>下拉菜单</title> <style> </style> <style> *{ padding: 0; margin: 0; list-style: none; } .container { 500px; height:230px; margin: 100px auto 0; } button { 50%; height: 30px; line-height: 30px; } h1{ 500px; margin: auto; } /*---上面不用看,重点在下面---*/ /* 以下是关于 .box对象 使用 transitionend(动画结束后执行的操作), 在jQuery中 使用on 绑定 transitionend ,.box 中有几个属性变化,transitionend就会执行几次。 如果只绑定一次,谨记使用 $box.off('transitionend').one('transitionend',function(){...}) */ .box { /* 还有一个属性在初始化的时候设置的,看下面JS的初始化 */ height: 200px; background: #f0e; padding-top: 20px; padding-bottom: 20px; overflow: hidden; } .fadeSlideUpDown { height: 0 !important; opacity: 0 !important; 0 !important; padding-top: 0 !important; padding-bottom: 0 !important; /* 设置高度过度类,必须设定上下内边距,因为标准模式的宽 = 上下内边距 + 实际宽度,如果是怪异模式那就可能不需要设置内边距 */ /* 同理:设置宽度过度类,必须设定左右内边距,因为标准模式的宽 = 上下内边距 + 实际宽度,如果是怪异模式那就可能不需要设置内边距 */ } .transition { -webkit-transition: all .5s; -moz-transition: all .5s; -ms-transition: all .5s; -o-transition: all .5s; transition: all .5s; } </style> </head> <body> <div class="container"> <button class="show">显示</button><button class="hide">隐藏</button> <div class="box"> <p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p><p>s</p> </div> <h1>显示有</h1> </div> <script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> <script> //获取jQuery对象 var $show = $('.show'), $hide = $('.hide'), $box = $('.box'); //初始化$el对象 function init($ele){ //这里的$box的高度是由内容撑开的,即没有设定高度,就是说浏览器不知道$box的高度 //所以使用过度属性 transition 时,不会有过渡效果, //浏览器解析 不知道的高度 0px 相互过度 ,就是瞬间显示隐藏。 //所以这里必须在初始化的时候就获取$box的宽高,并且显示的设置宽高即可解决。 //如果上下过度,就设定 height,左右过度就设置 width 即可。 $ele.width($ele.width()); $ele.height($ele.height()); //添加动画 $ele.addClass('transition'); //判断$ele对象是否显示,并且设置相应状态,并且添加相应转态必须添加的类 if ($ele.is(':hidden')) { $ele.data('status','hidden'); $ele.addClass('fadeSlideUpDown'); }else{ $ele.data('status','shown'); } } //给$box对象绑定以下四个事件。 $box.on('show shown hide hidden',function(e){ console.log(e.type) }) //给显示按钮绑定事件 $show.on('click',function(){ //如果状态相同,则不执行。 if ($box.data('status')==='show' || $box.data('status')==='shown') return; //事件触发之前,设置状态,并且触发指定事件,应用于:按需加载,即显示之前加载。下拉菜单 $box.data('status','show').trigger('show'); //这里使用一个异步调用的假象,对象显示20毫秒后,就执行一个显示的动画欺骗用户,这就是显示的效果。 $box.show(); setTimeout(function(){ //所有改变样式都使用 removeClass('xx') 添加类的方式防止浏览器重绘和回流,提高浏览器性能。 $box.removeClass('fadeSlideUpDown'); },20); //动画结束之后,设置状态,并且触发指定事件 $box.off('transitionend').on('transitionend',function(){ //事件 shown 会触发5次,因为这里使用on进行绑定 transitionend 动画结束后执行的事件 //而 $box 有5个属性变化,即有5次动画,每一次执行完成都会触发一次shown事件。 $box.data('status','shown').trigger('shown'); }) }) //给隐藏按钮绑定事件 $hide.on('click',function(){ //如果状态相同,则不执行。 if ($box.data('status')==='hide' || $box.data('status')==='hidden') return; //事件触发之前,设置状态,并且触发指定事件。 $box.data('status','hide').trigger('hide'); //所有改变样式都使用 addClass('xx') 添加类的方式防止浏览器重绘和回流,提高浏览器性能。 $box.addClass('fadeSlideUpDown'); $box.off('transitionend').on('transitionend',function(){ $box.hide(); //事件 hidden 会触发5次,因为这里使用on进行绑定 transitionend 动画结束后执行的事件 //而 $box 有5个属性变化,即有5次动画,每一次执行完成都会触发一次hidden事件。 //这里想要所有动画合并算一次,每次执行之前就移除之前的transitionend事件,重新开始执行 //所以这里要使用 $box.off('transitionend').one('transitionend') 进行绑定, //只绑定一次,每次执行前,移除之前绑定的transitionend。 //动画基本都必须在执行前移除之前的动画。 $box.data('status','hidden').trigger('hidden'); }) }) //初始化 init($box); </script> </body> </html>