如何在 html/css/js 中创建折叠树表?

Posted

技术标签:

【中文标题】如何在 html/css/js 中创建折叠树表?【英文标题】:How to create a collapsing tree table in html/css/js? 【发布时间】:2011-08-03 22:18:40 【问题描述】:

我有一些表格和分层的数据要显示。我想让用户能够展开和折叠节点。

有点像这样,除了功能性:

http://www.maxdesign.com.au/articles/tree-table/

解决此问题的最佳方法是什么?我不反对使用现成的插件。

【问题讨论】:

【参考方案1】:

SlickGrid 有这个功能,见tree demo。

如果您想自己构建,这里有一个示例 (jsFiddle demo):使用 data-depth 属性构建您的表格以指示树中项目的深度(levelX CSS 类仅用于样式缩进):

<table id="mytable">
    <tr data-depth="0" class="collapse level0">
        <td><span class="toggle collapse"></span>Item 1</td>
        <td>123</td>
    </tr>
    <tr data-depth="1" class="collapse level1">
        <td><span class="toggle"></span>Item 2</td>
        <td>123</td>
    </tr>
</table>

然后,当单击切换链接时,使用 javascript 隐藏所有 &lt;tr&gt; 元素,直到找到深度相等或更小的 &lt;tr&gt;(不包括那些已经折叠的):

$(function() 
    $('#mytable').on('click', '.toggle', function () 
        //Gets all <tr>'s  of greater depth below element in the table
        var findChildren = function (tr) 
            var depth = tr.data('depth');
            return tr.nextUntil($('tr').filter(function () 
                return $(this).data('depth') <= depth;
            ));
        ;

        var el = $(this);
        var tr = el.closest('tr'); //Get <tr> parent of toggle button
        var children = findChildren(tr);

        //Remove already collapsed nodes from children so that we don't
        //make them visible. 
        //(Confused? Remove this code and close Item 2, close Item 1 
        //then open Item 1 again, then you will understand)
        var subnodes = children.filter('.expand');
        subnodes.each(function () 
            var subnode = $(this);
            var subnodeChildren = findChildren(subnode);
            children = children.not(subnodeChildren);
        );

        //Change icon and hide/show children
        if (tr.hasClass('collapse')) 
            tr.removeClass('collapse').addClass('expand');
            children.hide();
         else 
            tr.removeClass('expand').addClass('collapse');
            children.show();
        
        return children;
    );
);

【讨论】:

非常好:-) 只是一个小的修正:注释应该是: // 获取所有深度更大的 .. NOT // 获取所有大于或等于的 depth.. 只有深度更深的 tr 才是我们想要隐藏的。我们想要展示的深度相同:)逻辑仍然正确。 此评论可能会被标记,但我不在乎,我要感谢您对可折叠树形网格的简单实现。你应该得到一千个赞! 看起来不错!当一切都崩溃时,你能告诉它最初是如何启动的吗? 【参考方案2】:

在现代浏览器中,您只需编写很少的代码即可创建可折叠树:

var tree = document.querySelectorAll('ul.tree a:not(:last-child)');
for(var i = 0; i < tree.length; i++)
    tree[i].addEventListener('click', function(e) 
        var parent = e.target.parentElement;
        var classList = parent.classList;
        if(classList.contains("open")) 
            classList.remove('open');
            var opensubs = parent.querySelectorAll(':scope .open');
            for(var i = 0; i < opensubs.length; i++)
                opensubs[i].classList.remove('open');
            
         else 
            classList.add('open');
        
        e.preventDefault();
    );
body 
    font-family: Arial;


ul.tree li 
    list-style-type: none;
    position: relative;


ul.tree li ul 
    display: none;


ul.tree li.open > ul 
    display: block;


ul.tree li a 
    color: black;
    text-decoration: none;


ul.tree li a:before 
    height: 1em;
    padding:0 .1em;
    font-size: .8em;
    display: block;
    position: absolute;
    left: -1.3em;
    top: .2em;


ul.tree li > a:not(:last-child):before 
    content: '+';


ul.tree li.open > a:not(:last-child):before 
    content: '-';
<ul class="tree">
  <li><a href="#">Part 1</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>

  <li><a href="#">Part 2</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>

  <li><a href="#">Part 3</a>
    <ul>
      <li><a href="#">Item A</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item B</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item C</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item D</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
      <li><a href="#">Item E</a>
        <ul>
          <li><a href="#">Sub-item 1</a></li>
          <li><a href="#">Sub-item 2</a></li>
          <li><a href="#">Sub-item 3</a></li>
        </ul>
      </li>
    </ul>
  </li>
</ul>

(另见this Fiddle

【讨论】:

感谢您的精彩回答。我正在尝试实施您的解决方案,但它似乎在我的设置中不起作用。我已经发布了一个关于这个的问题。请让我知道我做错了什么? ***.com/questions/43016555/… @AnandTyagi :您可以将您的代码发布在JSFiddle 或其他在线地方吗?我需要能够调试您的代码以找出问题所在! 感谢您的回复。 stackoverlow 的好心人已经解决了这个问题。 我知道这是旧的,但我发现这是最简单和最好的答案。在我的项目中完美运行 我认为您可能需要e.preventDefault() 才能使用它【参考方案3】:

jquery 是你的朋友。

http://docs.jquery.com/UI/Tree

如果您想自己制作,这里有一些高级指导:

将所有数据显示为&lt;ul /&gt; 元素,内部数据为嵌套&lt;ul /&gt;,然后使用jquery:

$('.ulClass').click(function() $(this).children().toggle(); );

我相信这是正确的。类似的东西。

编辑:

这是一个完整的例子。

 $(".Collapsable").click(function () 

    $(this).parent().children().toggle();
    $(this).toggle();

);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<ul>
    <li><span class="Collapsable">item 1</span><ul>
        <li><span class="Collapsable">item 1</span></li>
        <li><span class="Collapsable">item 2</span><ul>
            <li><span class="Collapsable">item 1</span></li>
            <li><span class="Collapsable">item 2</span></li>
            <li><span class="Collapsable">item 3</span></li>
            <li><span class="Collapsable">item 4</span></li>
        </ul>
        </li>
        <li><span class="Collapsable">item 3</span></li>
        <li><span class="Collapsable">item 4</span><ul>
            <li><span class="Collapsable">item 1</span></li>
            <li><span class="Collapsable">item 2</span></li>
            <li><span class="Collapsable">item 3</span></li>
            <li><span class="Collapsable">item 4</span></li>
        </ul>
        </li>
    </ul>
    </li>
    <li><span class="Collapsable">item 2</span><ul>
        <li><span class="Collapsable">item 1</span></li>
        <li><span class="Collapsable">item 2</span></li>
        <li><span class="Collapsable">item 3</span></li>
        <li><span class="Collapsable">item 4</span></li>
    </ul>
    </li>
    <li><span class="Collapsable">item 3</span><ul>
        <li><span class="Collapsable">item 1</span></li>
        <li><span class="Collapsable">item 2</span></li>
        <li><span class="Collapsable">item 3</span></li>
        <li><span class="Collapsable">item 4</span></li>
    </ul>
    </li>
    <li><span class="Collapsable">item 4</span></li>
</ul>

【讨论】:

这工作得很好,但对我来说,它从扩展所有路径开始 - 需要修改什么以便它从所有折叠到第一级开始? *编辑:我删除了我的消息进行编辑 - 感谢@joe_coolish 的快速回复。 .each() 是我需要的 没有问题 :) jQuery 太棒了!你可以这么快做这么多! p.s.,我更新了 jsfiddle 使其更可重用。这是新链接:jsfiddle.net/5Q8rJ/1 这正是我想要的,我只是想知道如何将背景设置为交替和全宽,即项目 1 中的项目 2 中的项目 4,具有与项目 1 相同的宽度背景?使其看起来像一个“树表”。 @user986697 - 我不确定你的意思?你说的是 CSS 吗? @user986697 - 如果这就是您所指的,请告诉我:jsfiddle.net/5Q8rJ/67【参考方案4】:

我也会把jsTree 扔进擂台。我发现它相当适合您的特定情况。它被打包为一个 jQuery 插件。

它可以从多种数据源运行,但我最喜欢的是一个简单的嵌套列表,如 @joe_coolish 或此处所述:

<ul>
  <li>
    Item 1
    <ul>
      <li>Item 1.1</li>
      ...
    </ul>
  </li>
  ...
</ul>

当 JS 在客户端不可用时,这种结构优雅地失败为静态树,并且从编码的角度来看很容易阅读和理解。

【讨论】:

【参考方案5】:

html 5 允许摘要标签、详细信息元素。这可用于查看或隐藏(折叠/展开)部分。 Link

【讨论】:

男人让我的希望在那里一秒钟。【参考方案6】:

你可以试试 jQuery treegrid (http://maxazan.github.io/jquery-treegrid/) 或 jQuery treetable (http://ludo.cubicphuse.nl/jquery-treetable/)

两者都使用 HTML &lt;table&gt; 标记格式并将样式设置为树。

jQuery 树表 使用data-tt-iddata-tt-parent-id 来确定树的父子节点。用法示例:

<table id="tree">
  <tr data-tt-id="1">
    <td>Parent</td>
  </tr>
  <tr data-tt-id="2" data-tt-parent-id="1">
    <td>Child</td>
  </tr>
</table>
$("#tree").treetable( expandable: true );

同时,jQuery treegrid 只使用类来设置树的样式。用法示例:

<table class="tree">
    <tr class="treegrid-1">
        <td>Root node</td><td>Additional info</td>
    </tr>
    <tr class="treegrid-2 treegrid-parent-1">
        <td>Node 1-1</td><td>Additional info</td>
    </tr>
    <tr class="treegrid-3 treegrid-parent-1">
        <td>Node 1-2</td><td>Additional info</td>
    </tr>
    <tr class="treegrid-4 treegrid-parent-3">
        <td>Node 1-2-1</td><td>Additional info</td>
    </tr>
</table>
<script type="text/javascript">
  $('.tree').treegrid();
</script>

【讨论】:

这对大数据有性能问题。仅 1500 个节点大约需要 1 分钟。

以上是关于如何在 html/css/js 中创建折叠树表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 PyQt 中创建可折叠的盒子

如何在 AMP 中创建类似 Bootstrap 的可折叠文件?

如何在 django 模板的引导程序中创建可折叠卡片?

RStudio 中的代码折叠:在代码中创建层次结构

Java 在Excel中创建多级分组折叠或展开分组

Java 在Excel中创建多级分组折叠或展开分组