showhide.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:360px; height:260px; background-color:pink; padding:20px; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"></div> <script src="../js/jquery.js"></script> <script> var silent={ show:function($elem,showCall,shownCall){ if(typeof showCall === "function") showCall(); $elem.show(); if(typeof shownCall === "function") shownCall(); }, hide:function($elem,hideCall,hiddenCall){ if(typeof showCall === "function") hideCall(); $elem.hide(); if(typeof shownCall === "function") hiddenCall(); } } var css3={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var box=$(".box"); var btnShow=$("#btn-show"); var btnHide=$("#btn-hide"); btnShow.on("click",function(){ silent.show(box,function(){ box.html("我要显示啦"); },function(){ setTimeout(function(){ box.html(box.html()+" 我已经显示啦"); },1000) }); }); btnHide.on("click",function(){ silent.hide(box,function(){ },function(){ }); }); </script> </body> </html>
效果图
这种方式有一个缺点,就是不适合多人协作的情况
因此选用发布订阅的方式,使用 jquery的 trigger 来触发事件
实现多人协作互不干扰
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:360px; height:260px; background-color:pink; padding:20px; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"></div> <script src="../js/jquery.js"></script> <script> var silent={ show:function($elem){ $elem.trigger("show"); $elem.show(); $elem.trigger("shown"); }, hide:function($elem){ $elem.trigger("hide"); $elem.hide(); $elem.trigger("hidden"); } } var css3={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var box=$(".box"); $("#btn-show").on("click",function(){ silent.show(box); }); $("#btn-hide").on("click",function(e){ silent.hide(box); }); // 模拟多人协作,A操作文本 box.on("show shown",function(e){ //console.log(e.type); if(e.type==="show"){ box.html("我要显示了"); } if(e.type==="shown"){ setTimeout(function(){ box.html(box.html()+"我已经显示了"); },1000); } }); // 模拟多人协作,B操作背景色 box.on("show shown",function(e){ if(e.type==="show"){ box.css("background-color","lightgreen"); } if(e.type==="shown"){ setTimeout(function(){ box.css("background-color","orange"); },1000); } }); </script> </body> </html>
效果图
需要增加判断机制,在已经显示的情况下,点击显示不再触发显示事件,避免性能浪费
解决连续点击多次触发的情况
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:360px; height:260px; background-color:pink; padding:20px; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"></div> <script src="../js/jquery.js"></script> <script> var silent={ show:function($elem){ // 显示状态下不再重复显示 if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; // 通过设置data-status的属性来判断当前的状态 $elem.data("status","show").trigger("show"); $elem.show(); $elem.data("status","shown").trigger("shown"); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); $elem.hide(); $elem.data("status","hidden").trigger("hidden"); } } var css3={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var box=$(".box"); $("#btn-show").on("click",function(){ silent.show(box); }); $("#btn-hide").on("click",function(e){ silent.hide(box); }); box.on("show shown",function(e){ //console.log(e.type); if(e.type==="show"){ box.html("我要显示了"); } if(e.type==="shown"){ setTimeout(function(){ box.html(box.html()+"我已经显示了"); },1000); } }); </script> </body> </html>
但由于初始时box并没有设置data-status属性,因此总能至少执行一次
因此需要引入初始化操作,根据元素的状态添加初始的data-status属性
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:360px; height:260px; background-color:pink; padding:20px; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"></div> <script src="../js/jquery.js"></script> <script> var silent={ init:function($elem){ // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); }else{ $elem.data("status","shown"); } }, show:function($elem){ // 显示状态下不再重复显示 if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; // 通过设置data-status的属性来判断当前的状态 $elem.data("status","show").trigger("show"); $elem.show(); $elem.data("status","shown").trigger("shown"); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); $elem.hide(); $elem.data("status","hidden").trigger("hidden"); } } var css3={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } var box=$(".box"); silent.init(box); $("#btn-show").on("click",function(){ silent.show(box); }); $("#btn-hide").on("click",function(e){ silent.hide(box); }); box.on("show shown",function(e){ //console.log(e.type); if(e.type==="show"){ box.html("我要显示了"); } if(e.type==="shown"){ setTimeout(function(){ box.html(box.html()+"我已经显示了"); },1000); } }); </script> </body> </html>
将封装的方法独立出去 showhide.js
上面这些是无动画效果的显示隐藏
下面来尝试css3动画效果的显示隐藏
首先给元素添加 transition 过渡
css部分添加
.transition{ -webkit-transition:all .5s; -moz-transition:all .5s; -ms-transition:all .5s; -o-transition:all .5s; transition:all .5s; }
html部分加上transition类
<div class="box transition"></div>
showhide.js
// css3动画方式 var css3={ fade:{ init:function($elem){ // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); }else{ $elem.data("status","shown"); } }, show:function($elem){ // 显示状态下不再重复显示 if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; // 通过设置data-status的属性来判断当前的状态 $elem.data("status","show").trigger("show"); $elem.show(); $elem.data("status","shown").trigger("shown"); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); $elem.hide(); $elem.data("status","hidden").trigger("hidden"); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
调用时
<script src="../js/showhide.js"></script> <script> var box=$(".box"); silent.init(box); $("#btn-show").on("click",function(){ css3.fade.show(box); }); $("#btn-hide").on("click",function(e){ css3.fade.hide(box); }); box.on("show shown",function(e){ //console.log(e.type); if(e.type==="show"){ box.html("我要显示了"); } if(e.type==="shown"){ setTimeout(function(){ box.html(box.html()+"我已经显示了"); },1000); } }); </script>
测试发现依然没有动画效果,这是因为元素设置的display:block或者display:none来显隐时默认就是没有动画的
有一种解决方法是:使用opacity来控制动画
缺点是当opacity设置为0时,元素依旧占位,并且可以响应事件
响应事件的问题可以用visibility来解决,占位的问题可以用absolute绝对定位来解决
showhide.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ position: absolute;/*解决占位问题*/ width:360px; height:260px; background-color:pink; padding:20px; } .transition{ -webkit-transition:all .5s; -moz-transition:all .5s; -ms-transition:all .5s; -o-transition:all .5s; transition:all .5s; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box transition"></div> <button class="btn">测试占位问题</button> <script src="../js/jquery.js"></script> <script src="../js/showhide.js"></script> <script> var box=$(".box"); silent.init(box); $("#btn-show").on("click",function(){ css3.fade.show(box); }); $("#btn-hide").on("click",function(e){ css3.fade.hide(box); }); box.on("show shown",function(e){ //console.log(e.type); if(e.type==="show"){ box.html("我要显示了"); } if(e.type==="shown"){ setTimeout(function(){ box.html(box.html()+"我已经显示了"); },1000); } }); //测试发现opacity为0时依然可以响应事件 box.on("click",function(){ alert("我还可以响应事件呢~"); }) </script> </body> </html>
showhide.js
// 无动画方式 var silent={ init:function($elem){ // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); }else{ $elem.data("status","shown"); } }, show:function($elem){ // 显示状态下不再重复显示 if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; // 通过设置data-status的属性来判断当前的状态 $elem.data("status","show").trigger("show"); $elem.show(); $elem.data("status","shown").trigger("shown"); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); $elem.hide(); $elem.data("status","hidden").trigger("hidden"); } } // css3动画方式 var css3={ fade:{ init:function($elem){ // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); }else{ $elem.data("status","shown"); } }, show:function($elem){ // 显示状态下不再重复显示 if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; // 通过设置data-status的属性来判断当前的状态 $elem.data("status","show").trigger("show"); $elem.css({ "opacity":1, "visibility":"visible" }); $elem.data("status","shown").trigger("shown"); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); $elem.css({ "opacity":0, "visibility":"hidden"//解决响应事件的问题 }); $elem.data("status","hidden").trigger("hidden"); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } // js动画方式 var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
效果图
但这并不是理想的解决方式
下面的解决方式是将 display 与 show hide 结合使用
showhide.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:360px; height:260px; background-color:pink; padding:20px; } .transition{ -webkit-transition:all .5s; -moz-transition:all .5s; -ms-transition:all .5s; -o-transition:all .5s; transition:all .5s; } .fadeOut{ opacity: 0; visibility: hidden; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box transition"></div> <button class="btn">测试占位问题</button> <script src="../js/jquery.js"></script> <script src="../js/showhide.js"></script> <script> var box=$(".box"); css3.fade.init(box); $("#btn-show").on("click",function(){ css3.fade.show(box); }); $("#btn-hide").on("click",function(e){ css3.fade.hide(box); }); box.on("show shown hide hidden",function(e){ //console.log(e.type); if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script> </body> </html>
showhide.js
// css3动画方式 var css3={ fade:{ init:function($elem){ // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); }else{ $elem.data("status","shown"); } }, show:function($elem){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); $elem.show(); // transitionend事件只需要添加一次,不需要每次都添加 // 因此使用one而不是on $elem.one("transitionend",function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) //利用延迟达到异步的效果 //在使用transition没有达到动画效果时,可以尝试将同步变为异步 setTimeout(function(){ $elem.removeClass("fadeOut"); },20); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); //transitionend是jquery判断动画执行完毕状态的事件 //在动画执行完毕后隐藏元素 $elem.one("transitionend",function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("fadeOut"); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
以上代码存在一个问题,就是当点击完显示立即点击隐藏时,显示的动画仍会持续,而不会立刻停止开始隐藏
因此需要在绑定transitionend事件之前先取消绑定之前的transitionend
// css3动画方式 var css3={ fade:{ init:function($elem){ $elem.addClass("transition"); // elem.is(":hidden")判断元素是否处于隐藏状态 if($elem.is(":hidden")){ $elem.data("status","hidden"); $elem.addClass("fadeOut"); }else{ $elem.data("status","shown"); } }, show:function($elem){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); $elem.show(); // transitionend事件只需要添加一次,不需要每次都添加 // 因此使用one而不是on $elem.off("transitionend").one("transitionend",function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) //利用延迟达到异步的效果 //在使用transition没有达到动画效果时,可以尝试将同步变为异步 setTimeout(function(){ $elem.removeClass("fadeOut"); },20); }, hide:function($elem){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); //transitionend是jquery判断动画执行完毕状态的事件 //在动画执行完毕后隐藏元素 $elem.off("transitionend").one("transitionend",function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("fadeOut"); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
由于css3方式和默认无动画方式存在大量的代码冗余,因此将重复部分提取成公共的函数
以下是代码瘦身后的结果:
showhide.js
// 公共init function init($elem,hiddenCall){ if($elem.is(":hidden")){ $elem.data("status","hidden"); if(typeof hiddenCall==="function") hiddenCall(); }else{ $elem.data("status","shown"); } } //公共show function show($elem,callback){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); callback(); } // 公共hide function hide($elem,callback){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); callback(); } // 无动画方式 var silent={ init:init, show:function($elem){ show($elem,function(){ $elem.show(); $elem.data("status","shown").trigger("shown"); }); }, hide:function($elem){ hide($elem,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); } } // css3动画方式 var css3={ fade:{ init:function($elem){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass("fadeOut"); }); }, show:function($elem){ show($elem,function(){ $elem.off("transitionend").one("transitionend",function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass("fadeOut"); },20); }); }, hide:function($elem){ hide($elem,function(){ $elem.off("transitionend").one("transitionend",function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("fadeOut"); }); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } // js动画方式 var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
transitionend 存在兼容性问题,需要做兼容处理(IE9以下不支持)
创建一个transition.js
(function(){ //判断transition属性是否存在 //存在:空字符串 //不存在:undefined //console.log(document.body.style.transition); var transitionName={ transition:"transitionend", mozTransition:"transitionend", webkitTransition:"webkitTransitionEnd", oTransition:"oTransitionEnd otransitionend" }; var transitionEnd=""; var isSupport=false; for(var name in transitionName){ if(document.body.style[name]!="undefined"){ //说明存在 transitionEnd=transitionName[name]; isSupport=true; break; } } //将局部变量作为一个全局变量的属性 window.mt=window.mt || {};//如果存在则继续存在,不存在则创建一个空对象 window.mt.transition=transitionEnd; window.mt.isSupport=isSupport; })();
在页面中测试
<script src="../js/jquery.js"></script> <script src="../js/transition.js"></script> <script src="../js/showhide.js"></script> <script> console.log(window.mt.transition);//transitionend console.log(window.mt.isSupport);//true </script>
showhide.js修改
var transition=window.mt.transition; // 公共init function init($elem,hiddenCall){ if($elem.is(":hidden")){ $elem.data("status","hidden"); if(typeof hiddenCall==="function") hiddenCall(); }else{ $elem.data("status","shown"); } } //公共show function show($elem,callback){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); callback(); } // 公共hide function hide($elem,callback){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); callback(); } // 无动画方式 var silent={ init:init, show:function($elem){ show($elem,function(){ $elem.show(); $elem.data("status","shown").trigger("shown"); }); }, hide:function($elem){ hide($elem,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); } } // css3动画方式 var css3={ fade:{ init:function($elem){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass("fadeOut"); }); }, show:function($elem){ show($elem,function(){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass("fadeOut"); },20); }); }, hide:function($elem){ hide($elem,function(){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("fadeOut"); }); } }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } } // js动画方式 var js={ fade:{ }, slideUpDown:{ }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
css3实现上下滚动
首先在css里添加 收缩状态的样式
/*收缩样式*/ .slideUpDownCollapse{ height:0 !important;/*避免因为优先级不够而无法生效*/ }
showhide.js中添加代码
// css3动画方式 var css3={ fade:{ init:function($elem){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass("fadeOut"); }); }, show:function($elem){ show($elem,function(){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass("fadeOut"); },20); }); }, hide:function($elem){ hide($elem,function(){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("fadeOut"); }); } }, slideUpDown:{ init:function($elem){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass("slideUpDownCollapse"); }); }, show:function($elem){ show($elem,function(){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass("slideUpDownCollapse"); },20); }); }, hide:function($elem){ hide($elem,function(){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass("slideUpDownCollapse"); }); } }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
调用
<script src="../js/jquery.js"></script> <script src="../js/transition.js"></script> <script src="../js/showhide.js"></script> <script> //console.log(window.mt.transition);//transitionend //console.log(window.mt.isSupport);//true var box=$(".box"); css3.slideUpDown.init(box); $("#btn-show").on("click",function(){ css3.slideUpDown.show(box); }); $("#btn-hide").on("click",function(e){ css3.slideUpDown.hide(box); }); box.on("show shown hide hidden",function(e){ //console.log(e.type); if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script>
这是依赖于修改元素的height来实现的,有可能元素自身没有height,而是被padding-top和padding-bottom给撑开的,如:
.box{ width:400px; /*height:300px;*//*height撑开*/ padding:150px 0;/*padding撑开*/ background-color:pink; }
这是需要在收缩类中将padding也设置为0
/*收缩样式*/ .slideUpDownCollapse{ height:0 !important;/*避免因为优先级不够而无法生效*/ padding-top:0 !important; padding-bottom:0 !important; }
有时元素既没有设置高度,也没有设置padding,而是被元素的内容给撑开的
这种情况下需要在初始化中先获取到元素被内容撑开后的高度,然后将元素高度设置为该高度
注意的是容器需要设置溢出隐藏
.box{ width:400px; /*height:300px;*//*height撑开*/ /*padding:150px 0;*//*padding撑开*/ background-color:pink; overflow:hidden;/*被内容撑开高度,需要设置溢出隐藏*/ }
showhide.js的初始化中添加:
init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 $elem.addClass("transition"); init($elem,function(){ $elem.addClass("slideUpDownCollapse"); }); },
可以发现在css3的不同方法中,也存在大量重复的代码,因此需要再次进行代码提取
提取css3的公共部分,在css3内部,命名可以使用 _ 开头(下划线开头)
slideLeftRight:和slideUpDown类似,将height的相关操作改为width,将padding-top/padding-bottom的相关操作改为padding-left/padding-right
fadeSlideUpDown:和slideUpDown类似,添加fadeOut和slideUpDownCollapse两个类
fadeSlideLeftRight:和slideLeftRight类似,添加fadeOut和slideLeftRightCollapse两个类
至此,css3的所有动画样式完成:
showhide.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:400px; /*height:300px;*//*height撑开*/ /*padding:150px 0;*//*padding撑开*/ background-color:pink; overflow:hidden;/*被内容撑开高度,需要设置溢出隐藏*/ } .transition{ -webkit-transition:all .5s; -moz-transition:all .5s; -ms-transition:all .5s; -o-transition:all .5s; transition:all .5s; } .fadeOut{ opacity: 0; visibility: hidden; } /*收缩样式*/ .slideUpDownCollapse{ height:0 !important;/*避免因为优先级不够而无法生效*/ padding-top:0 !important; padding-bottom:0 !important; } .slideLeftRightCollapse{ width:0 !important;/*避免因为优先级不够而无法生效*/ padding-left:0 !important; padding-right:0 !important; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"> 内容<br> 撑开<br> 高度<br> </div> <button class="btn">测试占位问题</button> <script src="../js/jquery.js"></script> <script src="../js/transition.js"></script> <script src="../js/showhide.js"></script> <script> //console.log(window.mt.transition);//transitionend //console.log(window.mt.isSupport);//true var box=$(".box"); css3.fadeSlideLeftRight.init(box); $("#btn-show").on("click",function(){ css3.fadeSlideLeftRight.show(box); }); $("#btn-hide").on("click",function(e){ css3.fadeSlideLeftRight.hide(box); }); box.on("show shown hide hidden",function(e){ //console.log(e.type); if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script> </body> </html>
showhide.js
// css3动画方式 var css3={ _init:function($elem,className){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass(className); }); }, _show:function($elem,className){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass(className); },20); }, _hide:function($elem,className){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass(className); }, //淡入淡出 fade:{ init:function($elem){ css3._init($elem,"fadeOut"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut"); }); } }, //上下滑动 slideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideUpDownCollapse"); }); } }, //左右滑动 slideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideLeftRightCollapse"); }); } }, //淡入淡出式上下滑动 fadeSlideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideUpDownCollapse"); }); } }, //淡入淡出式左右滑动 fadeSlideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideLeftRightCollapse"); }); } } }
接下来是js动画部分
首先fadeIn(fn) fadeOut(fn) slideDown(fn) slideUp(fn) 是jquery封装好的,直接拿来用就行
// js动画方式 var js={ fade:{ init:function($elem){ $elem.removeClass("transition"); //如果用js动画的元素设置了transition属性,会造成动画错乱 //需要确保元素没有transition属性 init($elem); }, show:function($elem){ show($elem,function(){ //jquery封装好的fadeIn(fn) $elem.stop().fadeIn(function(){ $elem.data("status","shown").trigger("shown"); }); }); }, hide:function($elem){ hide($elem,function(){ //jquery封装好的fadeOut(fn) $elem.stop().fadeOut(function(){ $elem.data("status","hidden").trigger("hidden"); }); }); } }, slideUpDown:{ init:function($elem){ $elem.removeClass("transition"); //如果用js动画的元素设置了transition属性,会造成动画错乱 //需要确保元素没有transition属性 init($elem); }, show:function($elem){ show($elem,function(){ //jquery封装好的slideDown(fn) $elem.stop().slideDown(function(){ $elem.data("status","shown").trigger("shown"); }); }); }, hide:function($elem){ hide($elem,function(){ $elem.stop().slideUp(function(){ $elem.data("status","hidden").trigger("hidden"); }); }); } }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
按照国际惯例,写到这里依旧是提取一下公共部分
// js动画方式 var js={ _init:function($elem){ $elem.removeClass("transition"); init($elem); }, _show:function($elem,mode){ show($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","shown").trigger("shown"); }); }); }, _hide:function($elem,mode){ hide($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","hidden").trigger("hidden"); }); }); }, fade:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"fadeIn"); }, hide:function($elem){ js._hide($elem,"fadeOut"); } }, slideUpDown:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"slideDown"); }, hide:function($elem){ js._hide($elem,"slideUp"); } }, slideLeftRight:{ }, fadeSlideUpDown:{ }, fadeSlideLeftRight:{ } }
slideLeftRight 没有封装好的jquery方法,因此需要自己写
大致思路就是通过改变width padding-left padding-right来实现
slideLeftRight:{ init:function($elem){ //获取元素最开始的样式属性 var styles={}; styles["width"]=$elem.css("width"); styles["padding-left"]=$elem.css("padding-left"); styles["padding-right"]=$elem.css("padding-right"); $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 $elem.removeClass("transition"); init($elem,function(){ $elem.css({ "width":0, "padding-left":0, "padding-right":0 }); }); }, show:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate({ "width":styles["width"], "padding-left":styles["padding-left"], "padding-right":styles["padding-right"] },function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, hide:function($elem){ hide($elem,function(){ //使用animate进行动画 $elem.stop().animate({ "width":0, "padding-left":0, "padding-right":0 },function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); } },
fadeSlideUpDown 与slideLeftRight类似,只是把width padding-left padding-right 换成height padding-top padding-bottom,再加上opacity
slideLeftRight:{ init:function($elem){ //获取元素最开始的样式属性 var styles={}; styles["width"]=$elem.css("width"); styles["padding-left"]=$elem.css("padding-left"); styles["padding-right"]=$elem.css("padding-right"); $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 $elem.removeClass("transition"); init($elem,function(){ $elem.css({ "width":0, "padding-left":0, "padding-right":0 }); }); }, show:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate({ "width":styles["width"], "padding-left":styles["padding-left"], "padding-right":styles["padding-right"] },function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, hide:function($elem){ hide($elem,function(){ //使用animate进行动画 $elem.stop().animate({ "width":0, "padding-left":0, "padding-right":0 },function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); } }, fadeSlideUpDown:{ init:function($elem){ //获取元素最开始的样式属性 var styles={}; styles["opacity"]=$elem.css("opacity"); styles["height"]=$elem.css("height"); styles["padding-top"]=$elem.css("padding-top"); styles["padding-bottom"]=$elem.css("padding-bottom"); $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 $elem.removeClass("transition"); init($elem,function(){ $elem.css({ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); }); }, show:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate({ "opacity":styles["opacity"], "height":styles["height"], "padding-top":styles["padding-top"], "padding-bottom":styles["padding-bottom"] },function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, hide:function($elem){ hide($elem,function(){ //使用animate进行动画 $elem.stop().animate({ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 },function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); } },
按照国际惯例继续提取公共部分
完成所有js动画部分
// js动画方式 var js={ _init:function($elem,callback){ $elem.removeClass("transition"); init($elem,callback); }, _show:function($elem,mode){ show($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","shown").trigger("shown"); }); }); }, _hide:function($elem,mode){ hide($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","hidden").trigger("hidden"); }); }); }, //自定义初始化公共部分 _customInit:function($elem,options){//options是一个对象,包含所有要改变的属性 var styles={}; for(var o in options){ styles[o]=$elem.css(o); } $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 js._init($elem,function(){ $elem.css(options); }); }, _customShow:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate(styles,function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, _customHide:function($elem,options){ hide($elem,function(){ $elem.stop().animate(options,function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); }, fade:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"fadeIn"); }, hide:function($elem){ js._hide($elem,"fadeOut"); } }, slideUpDown:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"slideDown"); }, hide:function($elem){ js._hide($elem,"slideUp"); } }, slideLeftRight:{ init:function($elem){ js._customInit($elem,{ "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "width":0, "padding-left":0, "padding-right":0 }); } }, fadeSlideUpDown:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); } }, fadeSlideLeftRight:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); } } }
最后,需要将以上这些代码封装成一个模块
封装好的showhide.js
(function($){ var transition=window.mt.transition;//支持的transition属性 var isSupport=window.mt.isSupport;//是否支持transition // 公共init function init($elem,hiddenCall){ if($elem.is(":hidden")){ $elem.data("status","hidden"); if(typeof hiddenCall==="function") hiddenCall(); }else{ $elem.data("status","shown"); } } //公共show function show($elem,callback){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); callback(); } // 公共hide function hide($elem,callback){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); callback(); } // 无动画方式 var silent={ init:init, show:function($elem){ show($elem,function(){ $elem.show(); $elem.data("status","shown").trigger("shown"); }); }, hide:function($elem){ hide($elem,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); } } // css3动画方式 var css3={ _init:function($elem,className){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass(className); }); }, _show:function($elem,className){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass(className); },20); }, _hide:function($elem,className){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass(className); }, //淡入淡出 fade:{ init:function($elem){ css3._init($elem,"fadeOut"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut"); }); } }, //上下滑动 slideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideUpDownCollapse"); }); } }, //左右滑动 slideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideLeftRightCollapse"); }); } }, //淡入淡出式上下滑动 fadeSlideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideUpDownCollapse"); }); } }, //淡入淡出式左右滑动 fadeSlideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideLeftRightCollapse"); }); } } } // js动画方式 var js={ _init:function($elem,callback){ $elem.removeClass("transition"); init($elem,callback); }, _show:function($elem,mode){ show($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","shown").trigger("shown"); }); }); }, _hide:function($elem,mode){ hide($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","hidden").trigger("hidden"); }); }); }, //自定义初始化公共部分 _customInit:function($elem,options){//options是一个对象,包含所有要改变的属性 var styles={}; for(var o in options){ styles[o]=$elem.css(o); } $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 js._init($elem,function(){ $elem.css(options); }); }, _customShow:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate(styles,function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, _customHide:function($elem,options){ hide($elem,function(){ $elem.stop().animate(options,function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); }, fade:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"fadeIn"); }, hide:function($elem){ js._hide($elem,"fadeOut"); } }, slideUpDown:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"slideDown"); }, hide:function($elem){ js._hide($elem,"slideUp"); } }, slideLeftRight:{ init:function($elem){ js._customInit($elem,{ "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "width":0, "padding-left":0, "padding-right":0 }); } }, fadeSlideUpDown:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); } }, fadeSlideLeftRight:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); } } } //设置默认参数 var defaults={ css3:false, js:false, animation:"fade" }; //封装一个函数 function showHide($elem,options){ //$.extend( target [, object1 ] [, objectN ] ) //如果只有一个参数,默认target是jquery对象,该方法用于为全局对象jQuery添加新的函数 //如果多个对象具有相同的属性,则后者会覆盖前者的属性值,用于合并对象 //此处,options参数会覆盖默认参数,合并后的参数会赋值给options对象 var options=$.extend({},defaults,options); var mode=null;if(options.css3 && isSupport){//css3动画 mode=css3[options.animation] || css3[defaults.animation];//容错 }else if(options.js){//js动画 mode=js[options.animation] || js[defaults.animation]; }else{//无动画 mode=silent; } mode.init($elem); //将对应的方法作为函数返回值 return { // $.proxy(函数,指向,参数) // 本来是用来改变函数内this指向,此处主要用来传参 // show:$.proxy(mode.show,this,$elem), // hide:$.proxy(mode.hide,this,$elem) show:mode.show, hide:mode.hide }; } window.mt=window.mt||{}; window.mt.showHide=showHide;//将showHide函数暴露在全局 })(jQuery);
补充一下这里 $.extend() 用法
$.extend( target, [obj1], [objn]
如果只有一个参数,则默认target是jquery,该方法用于为jquery添加新的函数
如果有多个参数,用于对象的合并,如果多个对象有相同的属性,则后面的会覆盖掉前面的
调用时:
<script> var box=$(".box"); //这种传参方式不够优雅 //此处需要传入box var showHide=window.mt.showHide(box,{ css3:true, animation:"fadeSlideUpDown" }); $("#btn-show").on("click",function(){ showHide.show(box);//此处需要传入box }); $("#btn-hide").on("click",function(e){ showHide.hide(box);//此处需要传入box }); box.on("show shown hide hidden",function(e){ if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script>
在以上代码调用中可以发现,box需要三次传入,比较繁琐
如果只想要传入一次,需要在showhide.js中做以下修改:
//将对应的方法作为函数返回值 return { // show:mode.show, // hide:mode.hide // $.proxy(函数,指向,参数) // 本来是用来改变函数内this指向,此处主要用来传参 show:$.proxy(mode.show,this,$elem), hide:$.proxy(mode.hide,this,$elem) };
这样的话调用时只有一处需要传入box
<script> var box=$(".box"); //只有这里需要传入box var showHide=window.mt.showHide(box,{ css3:true, animation:"fadeSlideUpDown" }); $("#btn-show").on("click",function(){ showHide.show();//使用$.proxy传参后,这里就不再需要传入参数 }); $("#btn-hide").on("click",function(e){ showHide.hide();//使用$.proxy传参后,这里就不再需要传入参数 }); box.on("show shown hide hidden",function(e){ if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script>
这里补充一下 $.proxy() 的用法:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>proxy</title> </head> <body> <button>点击我</button> <script src="../js/jquery.js"></script> <script> var obj={ oname:"cyy", otell:function(){ console.log(this.oname); } } obj.otell();//cyy this指向obj $("button").on("click",obj.otell);//点击按钮打印undefined // 原因:this指向调用函数的button元素,而button元素没有oname属性 $("button").on("click",$.proxy(obj.otell,obj));//cyy // 解决1:$.proxy(方法,this指向) $("button").on("click",$.proxy(obj,"otell"));//cyy //解决2:$.proxy(this指向,方法名) //解决1与解决2等价 </script> </body> </html>
参考上面解决1的写法: $.proxy( 方法, this指向,[参数] )
第三个参数是方法的传参,如果没有参数可以不传
一般来说$.proxy() 是用来改变this的指向,这里我们用来传参,这样在调用时就不需要重复传参
不过呢,以上这种调用方式还是不够优雅
最推荐的是使用jquery插件的方式调用,接下来改装代码
showhide.js
(function($){ var transition=window.mt.transition;//支持的transition属性 var isSupport=window.mt.isSupport;//是否支持transition // 公共init function init($elem,hiddenCall){ if($elem.is(":hidden")){ $elem.data("status","hidden"); if(typeof hiddenCall==="function") hiddenCall(); }else{ $elem.data("status","shown"); } } //公共show function show($elem,callback){ if($elem.data("status")==="show") return; if($elem.data("status")==="shown") return; $elem.data("status","show").trigger("show"); callback(); } // 公共hide function hide($elem,callback){ if($elem.data("status")==="hide") return; if($elem.data("status")==="hidden") return; $elem.data("status","hide").trigger("hide"); callback(); } // 无动画方式 var silent={ init:init, show:function($elem){ show($elem,function(){ $elem.show(); $elem.data("status","shown").trigger("shown"); }); }, hide:function($elem){ hide($elem,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); } } // css3动画方式 var css3={ _init:function($elem,className){ $elem.addClass("transition"); init($elem,function(){ $elem.addClass(className); }); }, _show:function($elem,className){ $elem.off(transition).one(transition,function(){//动画执行完毕后执行shown $elem.data("status","shown").trigger("shown"); }) $elem.show(); setTimeout(function(){ $elem.removeClass(className); },20); }, _hide:function($elem,className){ $elem.off(transition).one(transition,function(){ $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }) $elem.addClass(className); }, //淡入淡出 fade:{ init:function($elem){ css3._init($elem,"fadeOut"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut"); }); } }, //上下滑动 slideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideUpDownCollapse"); }); } }, //左右滑动 slideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"slideLeftRightCollapse"); }); } }, //淡入淡出式上下滑动 fadeSlideUpDown:{ init:function($elem){ $elem.height($elem.height());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideUpDownCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideUpDownCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideUpDownCollapse"); }); } }, //淡入淡出式左右滑动 fadeSlideLeftRight:{ init:function($elem){ $elem.width($elem.width());//获取到元素被内容撑开的高度,动态设置高度 css3._init($elem,"fadeOut slideLeftRightCollapse"); }, show:function($elem){ show($elem,function(){ css3._show($elem,"fadeOut slideLeftRightCollapse"); }); }, hide:function($elem){ hide($elem,function(){ css3._hide($elem,"fadeOut slideLeftRightCollapse"); }); } } } // js动画方式 var js={ _init:function($elem,callback){ $elem.removeClass("transition"); init($elem,callback); }, _show:function($elem,mode){ show($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","shown").trigger("shown"); }); }); }, _hide:function($elem,mode){ hide($elem,function(){ $elem.stop()[mode](function(){ $elem.data("status","hidden").trigger("hidden"); }); }); }, //自定义初始化公共部分 _customInit:function($elem,options){//options是一个对象,包含所有要改变的属性 var styles={}; for(var o in options){ styles[o]=$elem.css(o); } $elem.data("styles",styles);//如果不保存,则styles为局部,无法在其他函数中使用 js._init($elem,function(){ $elem.css(options); }); }, _customShow:function($elem){ show($elem,function(){ var styles=$elem.data("styles"); $elem.show(); //使用animate进行动画 $elem.stop().animate(styles,function(){//动画结束后的回调 $elem.data("status","shown").trigger("shown"); }); }); }, _customHide:function($elem,options){ hide($elem,function(){ $elem.stop().animate(options,function(){//动画结束后的回调 $elem.hide(); $elem.data("status","hidden").trigger("hidden"); }); }); }, fade:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"fadeIn"); }, hide:function($elem){ js._hide($elem,"fadeOut"); } }, slideUpDown:{ init:function($elem){ js._init($elem); }, show:function($elem){ js._show($elem,"slideDown"); }, hide:function($elem){ js._hide($elem,"slideUp"); } }, slideLeftRight:{ init:function($elem){ js._customInit($elem,{ "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "width":0, "padding-left":0, "padding-right":0 }); } }, fadeSlideUpDown:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "height":0, "padding-top":0, "padding-bottom":0 }); } }, fadeSlideLeftRight:{ init:function($elem){ js._customInit($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); }, show:function($elem){ js._customShow($elem); }, hide:function($elem){ js._customHide($elem,{ "opacity":0, "width":0, "padding-left":0, "padding-right":0 }); } } } //设置默认参数 var defaults={ css3:false, js:false, animation:"fade" }; //封装一个函数 function showHide($elem,options){ var mode=null; if(options.css3 && isSupport){//css3动画 mode=css3[options.animation] || css3[defaults.animation];//容错 }else if(options.js){//js动画 mode=js[options.animation] || js[defaults.animation]; }else{//无动画 mode=silent; } mode.init($elem); return { show:$.proxy(mode.show,this,$elem), hide:$.proxy(mode.hide,this,$elem) }; } // 改成jquery插件方式 $.fn.extend({ showHide:function(opt){ //this指向调用该插件的元素,这里是box //可能是一个元素,也可以是多个元素,因此使用each遍历 return this.each(function(){ var ui=$(this); // 如果options传递的是参数对象,则options属性与defaults属性进行合并,存入空对象中赋值给options // 如果options传递的不是对象,则为false,属性为defaults默认属性,并赋值给options // $.extend(target, obj1, objn) 对象合并 var options=$.extend({},defaults,typeof opt==="object" && opt); /* opt为参数对象时,如: box.showHide({ css3:true, animation:"slideLeftRight" }); */ var mode=ui.data("showHide"); //mode对象实例只需要生成一次 if(!mode){ mode=showHide(ui,options);//mode返回包含show和hide方法的一个对象 ui.data("showHide",mode); } /* opt为show或者hide字符串时,如: box.showHide("show"); */ //如果options是show或者hide的字符串,则执行方法 if(typeof mode[opt]==="function"){ mode[opt](); } }) } }); })(jQuery);
showhide.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>showhide</title> <link rel="stylesheet" href="../css/base.css"> <style> body{ width:400px; margin:0 auto; } button{ width:50%; height:30px; background: #abcdef; } .box{ width:400px; /*height:300px;*//*height撑开*/ /*padding:150px 0;*//*padding撑开*/ background-color:pink; overflow:hidden;/*被内容撑开高度,需要设置溢出隐藏*/ } .transition{ -webkit-transition:all .5s; -moz-transition:all .5s; -ms-transition:all .5s; -o-transition:all .5s; transition:all .5s; } .fadeOut{ opacity: 0; visibility: hidden; } /*收缩样式*/ .slideUpDownCollapse{ height:0 !important;/*避免因为优先级不够而无法生效*/ padding-top:0 !important; padding-bottom:0 !important; } .slideLeftRightCollapse{ width:0 !important;/*避免因为优先级不够而无法生效*/ padding-left:0 !important; padding-right:0 !important; } </style> </head> <body> <button id="btn-show" class="btn">显示</button><button id="btn-hide" class="btn">隐藏</button> <div class="box"> 内容<br> 撑开<br> 高度<br> </div> <button class="btn">测试占位问题</button> <script src="../js/jquery.js"></script> <script src="../js/transition.js"></script> <script src="../js/showhide.js"></script> <script> var box=$(".box"); //jquery插件方式传参 box.showHide({ css3:true, animation:"slideLeftRight" });//返回一个包含show和hide方法的对象mode $("#btn-show").on("click",function(){ //jquery插件方式调用 box.showHide("show"); }); $("#btn-hide").on("click",function(e){ //jquery插件方式调用 box.showHide("hide"); }); box.on("show shown hide hidden",function(e){ if(e.type==="show"){ console.log("show"); } if(e.type==="shown"){ console.log("shown"); } if(e.type==="hide"){ console.log("hide"); } if(e.type==="hidden"){ console.log("hidden"); } }); </script> </body> </html>
最后效果图
知识点补充:
trigger和triggerHandler的区别:
区别就是trigger会导致浏览器同名的默认行为的执行,如:
trigger('submit');不但会执行submit()函数的效果,也会执行表单提交的效果;
而triggerHandler就不会导致默认行为的执行。
另外,它们两个很相似,如果能够实现同样的效果,使用哪一个都行
$.fn $.fn.extend $.extend 区别:
$.fn
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>fnExtend</title> <style> .box{ width:200px; height:200px; padding:20px; text-align:center; line-height: 200px; border:1px solid #333; margin:100px auto; } </style> </head> <body> <div class="box">我是box</div> <script src="../js/jquery.js"></script> <script> //$.fn 原型对象上新增方法,一次只能添加一个 $.fn.pink=function(){ $(this).css("background-color","pink"); }; $(".box").pink();//div背景变粉色 $.pink();//不可以直接调用 </script> </body> </html>
$.fn.extend
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>fnExtend</title> <style> .box{ width:200px; height:200px; padding:20px; text-align:center; line-height: 200px; border:1px solid #333; margin:100px auto; } </style> </head> <body> <div class="box">我是box</div> <script src="../js/jquery.js"></script> <script> //$.fn.extend 原型对象上新增方法,可以在增加多个方法 $.fn.extend({ pink:function(){ $(this).css("background-color","pink"); }, blue:function(){ $(this).css("background-color","#abcdef"); } }); $(".box").blue();//div背景变蓝色 //$.blue();//不可以直接调用 // 合并对象功能,如果对象有相同的属性,则后面的会覆盖前面的 var obj1={ a:1, b:2 }; var obj2={ b:3, c:4 }; $.fn.extend(obj1,obj2);//将obj2合并到obj1中 console.log(obj1);//{a: 1, b: 3, c: 4} var newObj=$.fn.extend({},obj1,obj2);//将obj2和obj1合并到空对象中,赋值给newObj console.log(newObj);//{a: 1, b: 3, c: 4} </script> </body> </html>
$.extend
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>fnExtend</title> <style> .box{ width:200px; height:200px; padding:20px; text-align:center; line-height: 200px; border:1px solid #333; margin:100px auto; } </style> </head> <body> <div class="box">我是box</div> <script src="../js/jquery.js"></script> <script> //$.extend新增方法 $.extend({ pink:function(){ console.log("pink"); }, blue:function(){ console.log("blue"); } }); $.blue();//blue 需要直接调用 $(".box").blue();//报错 // 合并对象,功能与$.fn.extend相同 var obj1={ a:1, b:2 }; var obj2={ b:3, c:4 }; $.extend(obj1,obj2);//将obj2合并到obj1中 console.log(obj1);//{a: 1, b: 3, c: 4} </script> </body> </html>
总结:
$.fn
原型对象上新增方法,一次只能添加一个
不可以直接调用,需要有元素 elem.方法名()
$.fn.extend
原型对象上新增方法,可以增加多个方法
不可以直接调用,需要有元素 elem.方法名()
合并对象功能,如果对象有相同的属性,则后面的会覆盖前面的
$.extend
原型对象上新增方法,可以增加多个方法
必须直接调用,前面不能有元素 $.方法名()
合并对象功能,如果对象有相同的属性,则后面的会覆盖前面的