jQuery UI手风琴展开/收起全部

36

我正在项目中使用 jQuery UI Accordion,这个组件一次只允许打开一个面板。使用 Accordion 是适当的,因为通常我只是希望有一个面板处于打开状态。

然而,我需要提供一个“展开全部”链接,当点击后切换为“折叠全部”。我不想在这个需求上编写接近相同的手写Accordion功能代码,所以我想使用一些JS来实现这个需求,同时仍然使用 Accordion 组件。

问题: 如何使用 JavaScript/jQuery 来实现此功能,并仍然使用 jQuery UI "Accordion" 组件来提供标准功能?

下面是一个 fiddle 示例: http://jsfiddle.net/alecrust/a6Cu7/

12个回答

53

正如在jQuery UI论坛中所讨论的,您不应该使用手风琴来实现这个功能。

如果您想要一个看起来和行为像手风琴的东西,那是可以的。使用它们的类来设置样式,并实现您需要的任何功能。然后添加一个按钮来打开或关闭它们都是很简单的。示例

HTML

通过使用jquery-ui的类,我们可以使手风琴看起来就像“真正”的手风琴一样。

<div id="accordion" class="ui-accordion ui-widget ui-helper-reset">
    <h3 class="accordion-header ui-accordion-header ui-helper-reset ui-state-default ui-accordion-icons ui-corner-all">
        <span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-e"></span>
        Section 1
    </h3>
    <div class="ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom">
        Content 1
    </div>
</div>​

自己制作手风琴

通常我们只需要手风琴标题来切换其下一个兄弟元素的状态,即内容区域。我们还添加了两个自定义事件“show”和“hide”,稍后我们将会用到它们。

var headers = $('#accordion .accordion-header');
var contentAreas = $('#accordion .ui-accordion-content ').hide();
var expandLink = $('.accordion-expand-all');

headers.click(function() {
    var panel = $(this).next();
    var isOpen = panel.is(':visible');

    // open or close as necessary
    panel[isOpen? 'slideUp': 'slideDown']()
        // trigger the correct custom event
        .trigger(isOpen? 'hide': 'show');

    // stop the link from causing a pagescroll
    return false;
});

展开/折叠全部

我们使用布尔标志isAllOpen来标记按钮何时被更改,这也可以很容易地成为一个类或者是大型插件框架中的状态变量。

expandLink.click(function(){
    var isAllOpen = $(this).data('isAllOpen');

    contentAreas[isAllOpen? 'hide': 'show']()
        .trigger(isAllOpen? 'hide': 'show');
});

当面板全部展开时交换按钮

由于我们使用了自定义的“show”和“hide”事件,因此我们可以监听面板变化时所需的内容。唯一的特殊情况是“它们是否全部打开”,如果是,则按钮应为“折叠全部”,否则应为“展开全部”。

contentAreas.on({
    // whenever we open a panel, check to see if they're all open
    // if all open, swap the button to collapser
    show: function(){
        var isAllOpen = !contentAreas.is(':hidden');   
        if(isAllOpen){
            expandLink.text('Collapse All')
                .data('isAllOpen', true);
        }
    },
    // whenever we close a panel, check to see if they're all open
    // if not all open, swap the button to expander
    hide: function(){
        var isAllOpen = !contentAreas.is(':hidden');
        if(!isAllOpen){
            expandLink.text('Expand all')
            .data('isAllOpen', false);
        } 
    }
});​

编辑评论: 保持“仅打开1个面板”,除非您点击“展开全部”按钮,这实际上要简单得多。示例


2
有可能吗?简单的答案是否定的。你可以在很多不同的地方编辑源代码来实现,但那不是使用它,而是重写它。而且,“大”是相对的。jQuery UI手风琴源代码有738行,这只是因为它是建立在jquery.ui.core.js和jquery.ui.widget.js之上。 - Sinetheta
通过在最初隐藏所有内容面板的行中添加.first().show(),我更新了最终示例。 - Sinetheta
你的例子并不适用于所有元素,仅供参考。请确认其有效性。 - NoWar
我不确定我是否理解@DeA,那不是当前的行为吗?单击任何标题,其他部分关闭。展开全部,然后单击任何标题,它们都会关闭,但您单击的那个会重新打开。 - Sinetheta
@Sinetheta 非常感谢!哇,真的帮了我很大的忙。我没想到会有人回复这篇旧帖子。但是,还是非常感谢你! - DeA
显示剩余8条评论

21

很多看起来过于复杂。我只用以下一行代码就达到了想要的效果:

$(".ui-accordion-content").show();

JSFiddle


你比我更快一步了。我无意中自己发现了这个。 - Dexygen
2
$(".ui-accordion-content").slideDown(300); - Carel
$(".ui-accordion-content").toggle(); //启用显示/隐藏行为。唯一的缺点是任何打开的内容都将关闭,反之亦然。 - Joe Johnston

18

这是我的解决方案:

实际项目中的工作。

   $(function () {
    $("#accordion").accordion({collapsible:true, active:false});
    $('.open').click(function () {
        $('.ui-accordion-header').removeClass('ui-corner-all').addClass('ui-accordion-header-active ui-state-active ui-corner-top').attr({'aria-selected':'true','tabindex':'0'});
        $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-e').addClass('ui-icon-triangle-1-s');
        $('.ui-accordion-content').addClass('ui-accordion-content-active').attr({'aria-expanded':'true','aria-hidden':'false'}).show();
        $(this).hide();
        $('.close').show();
    });
    $('.close').click(function () {
        $('.ui-accordion-header').removeClass('ui-accordion-header-active ui-state-active ui-corner-top').addClass('ui-corner-all').attr({'aria-selected':'false','tabindex':'-1'});
        $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
        $('.ui-accordion-content').removeClass('ui-accordion-content-active').attr({'aria-expanded':'false','aria-hidden':'true'}).hide();
        $(this).hide();
        $('.open').show();
    });
    $('.ui-accordion-header').click(function () {
        $('.open').show();
        $('.close').show();
    });
});

http://jsfiddle.net/bigvax/hEApL/


4
你好,bigvax。jsfiddle链接很好,但是我有一些问题:以下是情景:1)点击“第一节”以打开它。2)点击“全部折叠”按钮关闭之前打开的部分。3)现在再次点击“第一节”,它不会在第一次单击时打开,你必须“单击两次”。我试图解决这个问题,但无法解决。请问你能告诉我如何解决这个问题吗? - jeewan
我遇到了与 @jeewan 相同的问题。 - DontFretBrett
同样的问题在这里。由于某种原因,第一次单击时它没有关闭。 - Leoncio
同样的问题,需要点击两次才能关闭。 - Pedro

7

考虑到需求,最终我发现这是最好的解决方案:

// Expand/Collapse all
$('.accordion-expand-collapse a').click(function() {
    $('.accordion .ui-accordion-header:not(.ui-state-active)').next().slideToggle();
    $(this).text($(this).text() == 'Expand all' ? 'Collapse all' : 'Expand all');
    $(this).toggleClass('collapse');
    return false;
});

JSFiddle链接已更新:http://jsfiddle.net/ccollins1544/r8j105de/4/


复制这段代码并在你的fiddle链接上运行,它将可以工作... 下面是与你的fiddle链接一起工作的代码:$('.accordion-expand-all a').click(function() { $('#accordion .ui-accordion-header:not(.ui-state-active)').next().slideToggle(); $(this).text($(this).text() == 'Expand all' ? 'Collapse all' : 'Expand all'); $(this).toggleClass('collapse'); return false; }); - Phung D. An
如果有嵌套的手风琴,这段代码还能正常工作吗? - NoWar

3
我不认为您可以使用手风琴来实现此目的,因为它专门设计为保持最多只有一个项目打开的属性。但是,即使您说您不想重新实现手风琴,您可能高估了所涉及的复杂性。
考虑以下场景,其中您有一堆垂直排列的元素,
++++++++++++++++++++
+     Header 1     +
++++++++++++++++++++
+                  +
+      Item 1      +
+                  +
++++++++++++++++++++
+     Header 2     +
++++++++++++++++++++
+                  +
+      Item 2      +
+                  +
++++++++++++++++++++

如果您懒得用DIV构建,还可以使用表格。每个项目块都可以具有itemBlock类。点击标题将导致所有itemBlock元素隐藏($(".itemBlock").hide())。然后,您可以使用jquery slideDown()函数展开标题下面的项目。现在,您已经基本实现了手风琴效果。要展开所有项目,请使用$(".itemBlock").show()或者如果您想要动画效果,则使用$(".itemBlock").slideDown(500)。要隐藏所有项目,只需使用$(".itemBlock").hide()。

谢谢,如果其他方法都失败了,我可能会选择这个。仍然抱有希望,能够添加在标准手风琴旁边的函数 :) - AlecRust
不幸的是,“只有一个打开”功能对于jquery ui手风琴来说是基本的,如果没有重写_create,就无法删除它,这实际上意味着分叉小部件。不过,我已经为您添加了一个答案,将所有内容都整理好了。 - Sinetheta
对我来说,整个小部件需要被分叉似乎很奇怪。我想要 jQuery UI 手风琴的所有现有功能(包括每个部分,仅打开一个面板),但希望能够通过按钮展开所有面板。也许这只是禁用手风琴小部件以呈现所有未折叠项目的问题? - AlecRust
1
抱歉,我误解了你的问题,因为“展开全部”与“仅打开1个”是互斥的。我已经修正了我的答案,并提供了一个示例,因为“除非您点击展开全部,否则仅打开1个”实际上更容易编写代码。 - Sinetheta

2

这是由Sinetheta编写的代码,已转换为jQuery插件: 将以下代码保存到js文件中。

$.fn.collapsible = function() {
    $(this).addClass("ui-accordion ui-widget ui-helper-reset");
    var headers = $(this).children("h3");
    headers.addClass("accordion-header ui-accordion-header ui-helper-reset ui-state-active ui-accordion-icons ui-corner-all");
    headers.append('<span class="ui-accordion-header-icon ui-icon ui-icon-triangle-1-s">');
    headers.click(function() {
        var header = $(this);
        var panel = $(this).next();
        var isOpen = panel.is(":visible");
        if(isOpen)  {
            panel.slideUp("fast", function() {
                panel.hide();
                header.removeClass("ui-state-active")
                    .addClass("ui-state-default")
                    .children("span").removeClass("ui-icon-triangle-1-s")
                        .addClass("ui-icon-triangle-1-e");
          });
        }
        else {
            panel.slideDown("fast", function() {
                panel.show();
                header.removeClass("ui-state-default")
                    .addClass("ui-state-active")
                    .children("span").removeClass("ui-icon-triangle-1-e")
                        .addClass("ui-icon-triangle-1-s");
          });
        }
    });
}; 

在您的 UI 页面中引用它并调用类似于 jQuery 手风琴调用:

$("#accordion").collapsible(); 

看起来更加简洁,避免在标记中添加任何类。


2
我赞同bigvax之前的评论,但您需要确保添加


        jQuery("#jQueryUIAccordion").({ active: false,
                              collapsible: true });

否则,您将无法在折叠后打开第一个手风琴。
    $('.close').click(function () {
    $('.ui-accordion-header').removeClass('ui-accordion-header-active ui-state-active ui-corner-top').addClass('ui-corner-all').attr({'aria-selected':'false','tabindex':'-1'});
    $('.ui-accordion-header .ui-icon').removeClass('ui-icon-triangle-1-s').addClass('ui-icon-triangle-1-e');
    $('.ui-accordion-content').removeClass('ui-accordion-content-active').attr({'aria-expanded':'false','aria-hidden':'true'}).hide();
   }

0

如果您可以接受每个面板都是独立的,那么只需将每个面板放在自己的手风琴中:

$(".accordion-panel").accordion({
            collapsible: true,
            multiple: true,
            active: 0
});

然后在 HTML 中,您可以将每个部分创建为自己的手风琴。

<div class="accordion-panel">
<h3 class="accordion-header">Section 1</h3>
    <div>
        <p>
        Mauris mauris ante, blandit et, ultrices a, suscipit eget, quam. Integer
        ut neque. Vivamus nisi metus, molestie vel, gravida in, condimentum sit
        amet, nunc. Nam a nibh. Donec suscipit eros. Nam mi. Proin viverra leo ut
        odio. Curabitur malesuada. Vestibulum a velit eu ante scelerisque vulputate.
        </p>
    </div>
</div>
<div class="accordion-panel">
<h3 class="accordion-header">Section 2</h3>
    <div>
        <p>
        Sed non urna. Donec et ante. Phasellus eu ligula. Vestibulum sit amet
        purus. Vivamus hendrerit, dolor at aliquet laoreet, mauris turpis porttitor
        velit, faucibus interdum tellus libero ac justo. Vivamus non quam. In
        suscipit faucibus urna.
        </p>
    </div>
</div>

0
Yes, it is possible. Put all div in separate accordion class as follows:

<script type="text/javascript" src="jquery.js"></script>
<script type="text/javascript" src="jquery-ui.js"></script>

<script type="text/javascript">

        $(function () {
            $("input[type=submit], button")
        .button()
        .click(function (event) {
            event.preventDefault();
        });
            $("#tabs").tabs();
            $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: 0



            });
        });

function expandAll()
{
  $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: 0

            });

            return false;   
}

function collapseAll()
{
  $(".accordion").accordion({
                heightStyle: "content",

                collapsible: true,
                active: false



            });
            return false;
}
</script>



<div class="accordion">
  <h3>Toggle 1</h3>
  <div >
    <p>text1.</p>
  </div>
</div>
<div class="accordion">
  <h3>Toggle 2</h3>
  <div >
    <p>text2.</p>
  </div>
</div>
<div class="accordion">
  <h3>Toggle 3</h3>
  <div >
    <p>text3.</p>
  </div>
</div>

0

我发现AlecRust的解决方案非常有帮助,但我添加了一些内容来解决一个问题:当您单击单个手风琴以展开它,然后单击按钮以展开时,它们都将被打开。但是,如果您再次单击按钮以折叠,则之前展开的单个手风琴不会折叠。

我使用了imageButton,但您也可以将该逻辑应用于按钮。

/*** Expand all ***/
$(".expandAll").click(function (event) {
    $('.accordion .ui-accordion-header:not(.ui-state-active)').next().slideDown();

    return false;
});

/*** Collapse all ***/
$(".collapseAll").click(function (event) {
    $('.accordion').accordion({
        collapsible: true,
        active: false
    });

    $('.accordion .ui-accordion-header').next().slideUp();

    return false;
});

另外,如果您在手风琴内部有手风琴,并且您想仅展开第二级的所有内容,您可以添加一个查询:

/*** Expand all Second Level ***/
$(".expandAll").click(function (event) {
    $('.accordion .ui-accordion-header:not(.ui-state-active)').nextAll(':has(.accordion .ui-accordion-header)').slideDown();

    return false;
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接