【问题标题】:expand/collapse table rows with JQuery使用 JQuery 展开/折叠表行
【发布时间】:2013-05-31 09:00:43
【问题描述】:

我想在单击标题列时展开和折叠表格行。我只想展开/折叠特定标题下的行(单击)。

这是我的表结构:

 <table border="0">
      <tr>
        <td colspan="2">Header</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td colspan="2">Header</td>
      </tr>
      <tr>
        <td>date</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
      <tr>
        <td>data</td>
        <td>data</td>
      </tr>
    </table>

关于如何完成这项任务的任何想法。使用 div 这个任务看起来很简单,但是我有我想要操作的表格数据。

我能想到的一个想法是在每一行中使用 css 类来区分每个标题下的行,并仅在单击标题时使用 JQuery 展开/折叠这些行。但是如果我的表有 10-15 个标题,那么跟踪 css 类似乎很困难。

请提出一个合适的方法来实现这一点。

【问题讨论】:

  • 我建议你使用嵌套列表(ulol 甚至 dl)而不是 table 元素。
  • 如果您使用标题单元格,为什么不也使用&lt;th&gt;
  • 是的,我可以使用 但它有什么用途?
  • 首先是语义,其次使用选择器语法更容易定位。
  • 虽然你可以拥有多个 tbody 元素,但我很确定你只能拥有 一个 thead 元素,所以我不确定这会有所帮助。不过,我发布了一个我认为满足您需求的答案。虽然它确实涉及向包含标题的tr 元素添加一个类名。

标签: jquery html css


【解决方案1】:

你可以这样试试:-

给标题行一个类说header,使用nextUntil 获取单击标题下的所有行,直到下一个标题。

JS

$('.header').click(function(){
    $(this).nextUntil('tr.header').slideToggle(1000);
});

HTML

<table border="0">
  <tr  class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>

Demo

另一个例子:

$('.header').click(function(){
   $(this).find('span').text(function(_, value){return value=='-'?'+':'-'});
    $(this).nextUntil('tr.header').slideToggle(100); // or just use "toggle()"
});

Demo

如果是动画切换,您还可以在切换完成后使用 Promise 切换跨度图标/文本。

$('.header').click(function () {
    var $this = $(this);
    $(this).nextUntil('tr.header').slideToggle(100).promise().done(function () {
        $this.find('span').text(function (_, value) {
            return value == '-' ? '+' : '-'
        });
    });
});

.promise()

.slideToggle()

或者只是用一个css伪元素来表示展开/折叠的标志,然后在表头切换一个类。

CSS:-

.header .sign:after{
  content:"+";
  display:inline-block;      
}
.header.expand .sign:after{
  content:"-";
}

JS:-

$(this).toggleClass('expand').nextUntil('tr.header').slideToggle(100);

Demo

【讨论】:

  • 只是好奇,但为什么不在下一行使用缓存的$this
  • 收到此错误:未捕获的 TypeError: Object # has no method 'nextUntil'
  • 作为补充,.toggle() 在有很多行需要切换时比.slideToggle(100); 效果更好。
  • 很好的答案,非常具有描述性。不知道我可以在一行半行中做到这一点。
  • @PSL 如何创建这种不同的方式?表格已折叠,您在点击时扩展?
【解决方案2】:

在不更改基于 HTML table 的结构的情况下,实现此目的的最简单方法是在包含标题的 tr 元素上使用类名,例如 .header,以给出:

<table border="0">
  <tr class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr class="header">
    <td colspan="2">Header</td>
  </tr>
  <tr>
    <td>date</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
  <tr>
    <td>data</td>
    <td>data</td>
  </tr>
</table>

还有 jQuery:

// bind a click-handler to the 'tr' elements with the 'header' class-name:
$('tr.header').click(function(){
    /* get all the subsequent 'tr' elements until the next 'tr.header',
       set the 'display' property to 'none' (if they're visible), to 'table-row'
       if they're not: */
    $(this).nextUntil('tr.header').css('display', function(i,v){
        return this.style.display === 'table-row' ? 'none' : 'table-row';
    });
});

JS Fiddle demo.

在链接的演示中,我使用 CSS 隐藏了 具有 header 类名的 tr 元素;但在实践中(尽管禁用 JavaScript 的用户相对较少)我建议使用 JavaScript 添加相关的类名,并酌情隐藏和显示:

// hide all 'tr' elements, then filter them to find...
$('tr').hide().filter(function () {
    // only those 'tr' elements that have 'td' elements with a 'colspan' attribute:
    return $(this).find('td[colspan]').length;
    // add the 'header' class to those found 'tr' elements
}).addClass('header')
    // set the display of those elements to 'table-row':
  .css('display', 'table-row')
    // bind the click-handler (as above)
  .click(function () {
    $(this).nextUntil('tr.header').css('display', function (i, v) {
        return this.style.display === 'table-row' ? 'none' : 'table-row';
    });
});

JS Fiddle demo.

参考资料:

【讨论】:

    【解决方案3】:

    我扩展了其中一个答案,但是我的功能有点不同。在我的版本中,不同的行形成不同的组。并且“标题”行会触发该特定组的折叠/展开。此外,每个单独的子组都会记住它所在的状态。听起来可能有点混乱,您可以使用 jsfiddle 测试我的版本。希望这段代码 sn-ps 对那里的人有所帮助!

    HTML

    <table border="0">
      <tr>
          <th>Header 1</th>
          <th>Header 2</th>
      </tr>
      <tr>
        <td class='group1'>Group 1</td>
        <td>data 2</td>
      </tr>
      <tr class='group1'>
        <td>data 3</td>
        <td>data 4</td>
      </tr>
      <tr>
        <td class='group2'>Group 2</td>
        <td>data 2</td>
      </tr>
      <tr class='group2'>
        <td>data 3</td>
        <td>data 4</td>
      </tr>
      <tr class='group2'>
        <td class='sub_group1'>Sub Group 1</td>
        <td>data 6</td>
      </tr>
      <tr class='group2 sub_group1'>
        <td>data 7</td>
        <td>data 8</td>
      </tr>
      <tr class='group2 sub_group1'>
        <td>data 9</td>
        <td>data 10</td>
      </tr>
      <tr class='group2 sub_group1'>
        <td class='sub_sub_group1'>Sub Sub Group 1</td>
        <td>data 11</td>
      </tr>
      <tr class='group2 sub_group1 sub_sub_group1'>
        <td>data 12</td>
        <td>data 13</td>
      </tr>
      <tr class='group2 sub_group1 sub_sub_group1'>
        <td>data 14</td>
        <td>data 15</td>
      </tr>
      <tr class='group2'>
        <td class='sub_group2'>Sub Group 2</td>
        <td>data 11</td>
      </tr>
      <tr class='group2 sub_group2'>
        <td>data 12</td>
        <td>data 13</td>
      </tr>
      <tr class='group2 sub_group2'>
        <td>data 14</td>
        <td>data 15</td>
      </tr>
    </table>
    

    CSS

    table, tr, td, th
    {
        border: 1px solid black;
        border-collapse:collapse;
    }
    
    img.button_open{
      content:url('http://code.stephenmorley.org/javascript/collapsible-lists/button-open.png');
      cursor:pointer;
    }
    
    img.button_closed{
      content: url('http://code.stephenmorley.org/javascript/collapsible-lists/button-closed.png');
      cursor:pointer;
    }
    

    JS

    function CreateGroup(group_name)
    {
        // Create Button(Image)
        $('td.' + group_name).prepend("<img class='" + group_name + " button_closed'> ");
        // Add Padding to Data
        $('tr.' + group_name).each(function () {
            var first_td = $(this).children('td').first();
            var padding_left = parseInt($(first_td).css('padding-left'));
            $(first_td).css('padding-left', String(padding_left + 25) + 'px');
        });
        RestoreGroup(group_name);
    
        // Tie toggle function to the button
        $('img.' + group_name).click(function(){
            ToggleGroup(group_name);
        });
    }
    
    function ToggleGroup(group_name)
    {
        ToggleButton($('img.' + group_name));
        RestoreGroup(group_name);
    }
    
    function RestoreGroup(group_name)
    {
        if ($('img.' + group_name).hasClass('button_open'))
        {
            // Open everything
            $('tr.' + group_name).show();
    
            // Close subgroups that been closed
            $('tr.' + group_name).find('img.button_closed').each(function () {
                sub_group_name = $(this).attr('class').split(/\s+/)[0];
                //console.log(sub_group_name);
                RestoreGroup(sub_group_name);
            });
        }
    
        if ($('img.' + group_name).hasClass('button_closed'))
        {
            // Close everything
            $('tr.' + group_name).hide();
        }
    }
    
    function ToggleButton(button)
    {
        $(button).toggleClass('button_open');
        $(button).toggleClass('button_closed');
    }
    
    CreateGroup('group1');
    CreateGroup('group2');
    CreateGroup('sub_group1');
    CreateGroup('sub_group2');
    CreateGroup('sub_sub_group1');
    

    DEMO

    【讨论】:

    • 非常好的结果,谢谢。如果使用wai-aria 使其更易于访问,它会变得更好。
    【解决方案4】:

    我喜欢提供的最简单的答案。然而,我不喜欢崩溃的波涛汹涌。所以我结合了这个问题的解决方案:How to Use slideDown (or show) function on a table row? 当行向上或向下滑动时,使其动画更流畅。它涉及必须将每个 td 的内容包装在一个 div 中。这允许它平滑地为折叠设置动画。当行展开时,它将替换 div,只替换为内容。

    所以这里是html:

    <table>
    <tr class="header">
        <td>CARS</td>
    </tr>
    <tr class="thing">
        <td>car</td>
    </tr>
    <tr class="thing">
        <td>truck</td>
    </tr>
    <tr class="header">
        <td>HOUSES</td>
    </tr>
    <tr class="thing">
        <td>split level</td>
    </tr>
    <tr class="thing">
        <td>trailer</td>
    </tr>
    

    这是 js

    $('.header').click(function(){
    if($(this).hasClass("collapsed")){
        $(this).nextUntil('tr.header')
        .find('td')
        .parent()
        .find('td > div')
        .slideDown("fast", function(){
            var $set = $(this);
            $set.replaceWith($set.contents());
        });
        $(this).removeClass("collapsed");
    } else {
        $(this).nextUntil('tr.header')
        .find('td')
        .wrapInner('<div style="display: block;" />')
        .parent()
        .find('td > div')
        .slideUp("fast");
        $(this).addClass("collapsed");
    }
    });
    

    查看这个小提琴的例子 https://jsfiddle.net/p9mtqhm7/52/

    【讨论】:

      【解决方案5】:

      我会说使用data- 属性将标题与其中的元素进行匹配。小提琴:http://jsfiddle.net/GbRAZ/1/

      HTML 改动预览:

         <tr class="header" id="header1">
          <td colspan="2">Header</td>
         </tr>
         <tr data-for="header1" style="display:none">
           <td>data</td>
           <td>data</td>
         </tr>
         <tr data-for="header1" style="display:none">
           <td>data</td>
           <td>data</td>
         </tr>
      

      JS 代码:

      $(".header").click(function () {
         $("[data-for="+this.id+"]").slideToggle("slow");
      });
      

      编辑: 但是,它涉及一些 HTML 更改。所以我不知道这是否是你想要的。一种更好的构建方法是使用&lt;th&gt; 或将整个html 更改为使用ul, ol, etc 甚至div &gt; span 设置。

      【讨论】:

        【解决方案6】:

        A JavaScript accordion 可以解决问题。

        This fiddle by W3Schools 只使用 javascript 让一个简单的任务变得更加简单,我在下面部分复制了它。

        <head>
        <style>
        button.accordion {
            background-color: #eee;
            color: #444;
            font-size: 15px;
            cursor: pointer;
        }
        
        button.accordion.active, button.accordion:hover {
            background-color: #ddd; 
        }
        
        div.panel {
            padding: 0 18px;
            display: none;
            background-color: white;
        }
        
        div.panel.show {
            display: block;
        }
        </style>
        </head><body>
        <script>
        var acc = document.getElementsByClassName("accordion");
        var i;
        
        for (i = 0; i < acc.length; i++) {
            acc[i].onclick = function(){
            this.classList.toggle("active");
            this.nextElementSibling.classList.toggle("show");
          }
        }
        </script>
        ...
        <button class="accordion">Section 1</button>
        <div class="panel">
          <p>Lorem ipsum dolor sit amet</p>
        </div>
        ...
        <button class="accordion">Table</button>
        <div class="panel">
          <p><table name="detail_table">...</table></p>
        </div>
        ...
        <button class="accordion"><table name="button_table">...</table></button>
        <div class="panel">
          <p>Lorem ipsum dolor sit amet</p>
          <table name="detail_table">...</table>
          <img src=...></img>
        </div>
        ...
        </body></html>
        

        如果使用 php,请不要忘记将 " 转换为 '。您还可以在按钮内使用数据表,它仍然可以工作。

        【讨论】:

          【解决方案7】:

          使用 jQuery 很简单...

           $('YOUR CLASS SELECTOR').click(function(){
          
                      $(this).toggle();
          });
          

          【讨论】:

            猜你喜欢
            相关资源
            最近更新 更多
            热门标签