继承Jquery的方法--tab滑动动画切换

1
HTML5 jQuery CSS C/C++ Go 8492 次浏览

前言

最近产品有个需求,要做个tab标签切换,这最基本的样式当然不在话下,但作为极客的我总要与众不同吧!于是大开脑洞,也就想出了个tab切换时候加个滑动动画(表笑我,谁让咱没达到UI交互设计师的高度呢),再然后正好想起本站曾经有个效果(传送门),于是乎找了这个效果demo给产品看,产品欣然同意了。

那么,问题又来了,之前的这个效果有几个弊端,也是我和产品认为不好的:

  1. 不同tab页的内容高度不同,差距可能还比较大,不能用一个统一的固定高度来搞
  2. 例如从tab1跳到tab3这种跨项的情况,原则上是不能让用户在动画过程中看到tab2内容的(不要问为什么,这就是极客精神),如果从tab1跳到tab5,中间跨了3项,这体验总感觉略low啊

因此,轮子还得造!

需求功能

  1. 不固定高度。高度不同的tab页直接也可以自适应切换
  2. 跨项无缝切换。跨项切换时候不会看到中间项内容
  3. tab标题也增加滑动动画

思路分析

  1. 所谓不固定高度,那么只有在即将动画时拿到切换前和切换后两个tab页中较大的高度进行设置
  2. 跨项不显示中间项的话,那么只有“造假”了:把切换前和切换后的两个tab页克隆下来构造个动画区,放到最前面,走个过场动画,同时隐藏掉原来真实tab页,结束后remove掉动画区,同时将真实tab页展现(本人觉得这是个简单的笨办法,如果大神有更合适的思路可以留言讨论)

代码赏析

以下是jquery插件的原代码,注释可以说的手把手的教学!每一步都写了注释,重点就是看“tab页动画部分”的注释

	
  1. $.fn.extend({
  2. tab: function (index) {//index:初始化后第几个tab显示,默认0
  3. this.each(function () {
  4. var animating = false;//动画进行中的标识,保证不会在动画过程中再次执行动画
  5. var $this = $(this);
  6. var $tabCard = $this.children(".tab-card");
  7. var $tabCards = $tabCard.children();
  8. var $tabPaper = $this.children(".tab-paper");
  9. var $tabPapers = $tabPaper.children();
  10. var curIndex = $tabCards.filter(".cur").index();//通过cur获取当前tab页序号
  11. curIndex = index || (curIndex == -1 ? 0 : curIndex) || 0;//参数index优先级最高
  12. //初始化cur状态
  13. $tabCards.removeClass("cur");
  14. $tabPapers.removeClass("cur");
  15. $tabCards.eq(curIndex).addClass("cur");
  16. $tabPapers.eq(curIndex).addClass("cur");
  17. /*************************tab标签的动画部分*************************/
  18. /*此段代码借鉴lavaLamp,构造一个绝对定位的back li在滑动*/
  19. $tabCard.each(function () {
  20. var b = $(this), noop = function () {
  21. }, $back = $('<li class="back"><div class="left"></div></li>').appendTo(b), $li = $("li", this), curr = $("li.cur", this)[0] || $($li[0]).addClass("cur")[0];
  22. $li.not(".back").hover(function () {
  23. move(this)
  24. }, noop);
  25. $(this).hover(noop, function () {
  26. move(curr)
  27. });
  28. $li.not(".back").click(function (e) {
  29. if (!animating) {
  30. setCurr(this);
  31. }
  32. });
  33. setCurr(curr);
  34. function setCurr(a) {
  35. $back.css({"left": a.offsetLeft + "px", "width": a.offsetWidth + "px"});
  36. curr = a
  37. }
  38.  
  39. function move(a) {
  40. $back.each(function () {
  41. $(this).dequeue()
  42. }).animate({width: a.offsetWidth, left: a.offsetLeft}, 500, "easeOutBack");
  43. }
  44. });
  45. /*************************tab页动画部分*************************/
  46. /*tab标签点击*/
  47. $tabCards.on("click", function () {
  48. slide(this)
  49. });
  50. /*直接更改当前tab标签样式*/
  51. function changeCard(the) {
  52. var $t = $(the);
  53. $t.addClass("cur").siblings().removeClass("cur");
  54. }
  55.  
  56. /*直接切换tab页内容位置*/
  57. function changePaper(the) {
  58. var $t = $(the);
  59. var ci = $t.index();
  60. $tabPapers.eq(ci).addClass("cur").siblings().removeClass("cur");
  61. curIndex = ci;
  62. $tabPaper.height($tabPapers.eq(ci).height());
  63. }
  64.  
  65. /*tab页滑动动画*/
  66. function slide(the) {
  67. if (!animating) {
  68. var $t = $(the);
  69. changeCard(the);
  70. var ci = $t.index();
  71. // 当前页和切换页相同时 直接返回
  72. if (ci == curIndex) return;
  73. var $fromPaper = $tabPapers.eq(curIndex);
  74. var $toPaper = $tabPapers.eq(ci);
  75. //克隆一个当前页和一个切换页,后续只做动画使用
  76. var $fromPaper_clone = $fromPaper.clone();
  77. var $toPaper_clone = $toPaper.clone();
  78. //获取tab页宽度,padding样式
  79. var paperWidth = $tabPaper.width();
  80. var paperPadding = $tabPaper.css("padding");
  81. var paperPaddingLeft = parseInt($tabPaper.css("padding-left"));
  82. //通过宽度和padding计算总宽度
  83. var paperWidthTotal = paperWidth + 2 * paperPaddingLeft;
  84. //比较当前页和切换页的高度,选取高的作为动画时的高度
  85. var paperHeight = Math.max($fromPaper.height(), $toPaper.height());
  86. //定义动画区样式
  87. $fromPaper_clone.css({
  88. float: "left",
  89. display: "block",
  90. background: "#fff",
  91. padding: paperPadding,
  92. width: paperWidth,
  93. height: $fromPaper.height()
  94. });
  95. $toPaper_clone.css({
  96. float: "left",
  97. "display": "block",
  98. background: "#fff",
  99. padding: paperPadding,
  100. "width": paperWidth,
  101. height: $toPaper.height()
  102. });
  103. //定义动画区,此动画区只作动画使用,动画完成后立刻remove
  104. var $animateArea = $("<div></div>");
  105. $animateArea.css({
  106. "position": "absolute",
  107. "top": 0,
  108. left: 0,
  109. width: 2 * paperWidthTotal,
  110. height: paperHeight
  111. });
  112. //定义动画到达的位置,比较切换页和当前页序号大小,以此决定动画是向前滑动还是向后滑动
  113. var animateLeft;
  114. if (ci > curIndex) {
  115. $animateArea.css("left", 0).append($fromPaper_clone).append($toPaper_clone);
  116. animateLeft = -paperWidthTotal;
  117. } else if (ci < curIndex) {
  118. $animateArea.css("left", -paperWidthTotal).append($toPaper_clone).append($fromPaper_clone);
  119. animateLeft = 0;
  120. }
  121. //动画区被加载,同时tab页高度改变,真实tab透明隐藏
  122. $tabPaper.append($animateArea);
  123. $tabPaper.height(paperHeight);
  124. $tabPapers.css({"opacity": 0, filter: "alpha(opacity=0)"});
  125. //执行动画,动画结束后remove掉动画区,直接定位并显示出真实tab页内容
  126. animating = true;
  127. $animateArea.animate({left: animateLeft}, 500, "easeOutQuint", function () {
  128. $animateArea.remove();
  129. changePaper(the);
  130. $tabPapers.css({"opacity": 1, filter: "alpha(opacity=100)"});
  131. animating = false;
  132. });
  133. }
  134. }
  135. });
  136. }
  137. });

效果预览~~

在线代码调试:地址

 原文链接:http://www.gbtags.com/gb/share/5781.htm

请尽量让自己的答案能够对别人有帮助

5个答案

默认排序 按投票排序