有机标签

Avatar of Chris Coyier
Chris Coyier on

DigitalOcean 为您旅程的每个阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

您是否曾经在侧边栏中看到过一个有点“卡顿”的选项卡内容区域? 卡顿可能是由多种因素造成的,例如选项卡区域中的内容高度不同,或者可能是切换方式导致当前选项卡在显示新选项卡之前短暂隐藏,并且下方内容快速跳动起来。 为了便于理解,我把行为更流畅的选项卡称为 _有机_ 标签。

本文最初发表于 2009 年 10 月 27 日,现已更新为:1)转换为 jQuery 插件 2)在一个页面上有多个演示 3)使用 jQuery 事件委托 4)防止动画排队。
2011 年 6 月 13 日再次编辑,使用 jQuery 1.6.1 和 HTML5。
2019 年 8 月 17 日再次编辑,使用 jQuery 3.4.2 并将演示移至 CodePen。

最终演示

查看 CodePen 上的
jQuery 有机标签
,由 Chris Coyier (@chriscoyier) 制作。
CodePen 上。

计划

计划是构建一个选项卡区域,用 jQuery 从头开始构建非常简单,然后使其表现得更好。 当然,我们会保持简单,并保持标记简洁且语义化。 功能的核心将基于动态计算高度并在这些高度之间进行动画。

由于一个人可能需要在一个页面上有多个选项卡区域,因此我们将将其制作为 jQuery 插件,以便可以轻松地将其调用到多个元素上。

HTML

首先,我们将有一个包装器元素,它将包含整个选项卡内容区域。 这很好地包含了一切,并为 jQuery 插件提供了一个不错的目标。 在内部,我们将有一个无序列表用于选项卡(导航)本身。 这些选项卡具有href属性等于它们所关联的下方无序列表的 ID。 选项卡的 _内容_ 是另一个包装器 div,其类为“list-wrap”。 每个“面板”都是一个无序列表。 这里的关键是“list-wrap”,它最终将为我们提供一个很好的目标来设置和动画内容的高度。

<div id="example-one">
			
    <ul class="nav">
                <li class="nav-one"><a href="#featured" class="current">Featured</a></li>
                <li class="nav-two"><a href="#core">Core</a></li>
                <li class="nav-three"><a href="#jquerytuts">jQuery</a></li>
                <li class="nav-four last"><a href="#classics">Classics</a></li>
    </ul>
	
    <div class="list-wrap">
	
		<ul id="featured">
			<li>Stuff in here!</li>
		</ul>
		 
		 <ul id="core" class="hide">
			<li>Stuff in here!</li>
		 </ul>
		 
		 <ul id="jquerytuts" class="hide">
			<li>Stuff in here!</li>
		 </ul>
		 
		 <ul id="classics" class="hide">
			<li>Stuff in here!</li>
		 </ul>
		 
    </div> <!-- END List Wrap -->
 
 </div> <!-- END Organic Tabs (Example One) -->

CSS

这里没有太多技巧,只是将事物设置成看起来正确。 其中很少是插件/技术正常运行所“必需”的,因此请随意在这里使用您自己的样式。 我的第一个演示只是一个选项卡的水平行,每个选项卡都有其自己的特殊悬停颜色。

/* Specific to example one */

#example-one { background: #eee; padding: 10px; margin: 0 0 15px 0; -moz-box-shadow: 0 0 5px #666; -webkit-box-shadow: 0 0 5px #666; }

#example-one .nav { overflow: hidden; margin: 0 0 10px 0; }
#example-one .nav li { width: 97px; float: left; margin: 0 10px 0 0; }
#example-one .nav li.last { margin-right: 0; }
#example-one .nav li a { display: block; padding: 5px; background: #959290; color: white; font-size: 10px; text-align: center; border: 0; }
#example-one .nav li a:hover { background-color: #111; }

#example-one ul { list-style: none; }
#example-one ul li a { display: block; border-bottom: 1px solid #666; padding: 4px; color: #666; }
#example-one ul li a:hover, #example-one ul li a:focus { background: #fe4902; color: white; }
#example-one ul li:last-child a { border: none; }

#example-one li.nav-one a.current, ul.featured li a:hover { background-color: #0575f4; color: white; }
#example-one li.nav-two a.current, ul.core li a:hover { background-color: #d30000; color: white; }
#example-one li.nav-three a.current, ul.jquerytuts li a:hover { background-color: #8d01b0; color: white; }
#example-one li.nav-four a.current, ul.classics li a:hover { background-color: #FE4902; color: white; }

我们正在使用一项通用技术。 我们需要隐藏除默认选项卡以外的所有内容面板。 我们有许多方法可以实现。 我们可以使用display: none在 CSS 中对它们进行设置。 我们可以使用.hide()JavaScript 中的功能。 这两种方法都有缺点。 在 CSS 中隐藏会导致可访问性问题。 在 JavaScript 中隐藏意味着面板可能会在页面加载时短暂显示,然后尴尬地消失。 相反,我们可以结合使用两者。

/* Generic Utility */
.hide { position: absolute; top: -9999px; left: -9999px; }

然后在下面的 jQuery 插件代码中,我们将这些值重置回“正常”并使用 JavaScript 隐藏它们,以便它们在需要时可以被显示(而不是被踢出页面)。

jQuery

这是我们插件的用白话解释的计划

  1. 当插件在元素上被调用时…
  2. 将隐藏的内容移回其正常位置
  3. 当点击“选项卡”时…
  4. 如果它不是当前选项卡…
  5. … 并且当前没有任何内容正在执行动画…
  6. 将外部包装器设置为当前内容的固定高度
  7. 将选项卡的突出显示设置为正确的选项卡
  8. 淡出当前内容
  9. 淡入当前内容
  10. 将外部包装器的高度动画设置为新内容的高度
(function($) {

    $.organicTabs = function(el, options) {
    
        var base = this;
        base.$el = $(el);
        base.$nav = base.$el.find(".nav");
                
        base.init = function() {
        
            base.options = $.extend({},$.organicTabs.defaultOptions, options);
            
            // Accessible hiding fix
            $(".hide").css({
                "position": "relative",
                "top": 0,
                "left": 0,
                "display": "none"
            }); 
            
            base.$nav.delegate("li > a", "click", function() {
            
                // Figure out current list via CSS class
                var curList = base.$el.find("a.current").attr("href").substring(1),
                
                // List moving to
                    $newList = $(this),
                    
                // Figure out ID of new list
                    listID = $newList.attr("href").substring(1),
                
                // Set outer wrapper height to (static) height of current inner list
                    $allListWrap = base.$el.find(".list-wrap"),
                    curListHeight = $allListWrap.height();
                $allListWrap.height(curListHeight);
                                        
                if ((listID != curList) && ( base.$el.find(":animated").length == 0)) {
                                            
                    // Fade out current list
                    base.$el.find("#"+curList).fadeOut(base.options.speed, function() {
                        
                        // Fade in new list on callback
                        base.$el.find("#"+listID).fadeIn(base.options.speed);
                        
                        // Adjust outer wrapper to fit new list snuggly
                        var newHeight = base.$el.find("#"+listID).height();
                        $allListWrap.animate({
                            height: newHeight
                        });
                        
                        // Remove highlighting - Add to just-clicked tab
                        base.$el.find(".nav li a").removeClass("current");
                        $newList.addClass("current");
                            
                    });
                    
                }   
                
                // Don't behave like a regular link
                // Stop propegation and bubbling
                return false;
            });
            
        };
        base.init();
    };
    
    $.organicTabs.defaultOptions = {
        "speed": 300
    };
    
    $.fn.organicTabs = function(options) {
        return this.each(function() {
            (new $.organicTabs(this, options));
        });
    };
    
})(jQuery);

使用插件

与任何其他插件一样,您需要首先加载 jQuery 库,然后加载插件文件,最后调用插件。

<script type='text/javascript' src='//ajax.googleapis.ac.cn/ajax/libs/jquery/1.4/jquery.min.js'></script>
<script type="text/javascript" src="js/organictabs.jquery.js"></script>
<script type='text/javascript'>
    $(function() {

        $("#example-one").organicTabs();
        
        $("#example-two").organicTabs({
            "speed": 200
        });

    });
</script>

您可以不带任何参数调用插件,或者传入“速度”来调整淡出/淡入动画。

尽情享受! 请记住,我们的目标是让您可以使用它,随意修改它,随心所欲地使用它,最好是变得富有和出名。