6

我正在寻找一种使用 jQuery 展开/折叠分层表行的有效方法。问题是,展开和折叠功能不同。

  • 最初,只level_0显示具有类的行,隐藏所有其他行。
  • 展开应该只显示下一个级别,因此单击行id=10应该只使行可见id=11并且id=14可见。
  • 另一方面,折叠应该折叠所有连续行,其级别比当前行更深。例如,单击行上的折叠id=10应该隐藏具有 ids 的行11, 12, 13, 14,如果它们是可见的。

表数据如下所示:

<table id="mytable">
    <tr class="level_0" id="10">...</td>
    <tr class="level_1 parent_10" id="11">...</td>
    <tr class="level_2 parent_11" id="12">...</td>
    <tr class="level_2 parent_11" id="13">...</td>
    <tr class="level_1 parent_10" id="14">...</td>
    <tr class="level_0" id="15">...</td>
</table>

我的非工作解决方案:

$('#mytable tr').live('click', function() {
  var toggleClass = 'parent_' + $(this).attr('id');
  $(this).nextAll('tr').each(function() {
    if ($(this).is('.'+toggleClass)) {
      $(this).toggleClass("showme");
    }
  });
});

问题是,它只会折叠下一级行。单击的行下方的可见和更深层次的行仍会显示。


谁能给我一些提示,告诉我如何以有效的方式做到这一点?如果需要,可以调整 HTML 代码。

感谢您的任何提示。

4

3 回答 3

2

您帖子中的表格 html 无效(由 td 括起来的 tr)。在结构正确的表上,此代码有效。

$("tr.level_0").live("click", function () {
  $(this).nextUntil(".level_0").toggle();
});
于 2011-02-13T08:44:50.040 回答
0

我已经为多个层次结构创建了一个版本,作为另一个问题的答案

您的表的 jQuery 将是:

var treeTable = {
    parentClassPrefix : '',
    collapsedClass : 'collapsed',
    init : function(parentClassPrefix) {
        this.parentClassPrefix = parentClassPrefix;
        $('table').on('click', 'tr', function () { 
            treeTable.toggleRowChildren($(this));
        });
    },
    toggleRowChildren : function(parentRow) {
        var childClass = this.parentClassPrefix+parentRow.attr('id');
        var childrenRows = $('tr', parentRow.parent()).filter('.'+childClass);
        childrenRows.toggle();
        childrenRows.each(function(){
            if (!$(this).hasClass(treeTable.collapsedClass)) {
                treeTable.toggleRowChildren($(this));
            }
        });
        parentRow.toggleClass(this.collapsedClass);
    }
};

treeTable.init('parent_');

请参阅此JSFiddle以了解它的工作原理。

优化

我有一个稍微不同的表结构,它涉及指定父母和孩子,以便搜索更有效。

然后,我还制作了一个jQuery 分层表行,从中切换 Gist并将其转换为具有优化的对象化 javascript。优化来自http://24ways.org/2011/your-jquery-now-with-less-suck/

具体来说:

事件委托在表上而不是在行上。

$('table').on('click', 'tr.'+treeTable.parentClass, function () {
    treeTable.toggleRowChildren($(this));
});

缓存孩子的选择。

在 .childClass 上使用较快的元素选择器,然后使用较慢的过滤器

var childrenRows = $('tr', parentRow.parent()).filter('.'+childClass);
于 2014-01-27T17:03:12.483 回答
0

我认为您将需要更多代码,以便您可以在关闭打开状态下处理所有行的点击。

我添加了一个类开关来指示行何时打开,并根据其状态对点击进行不同的处理。两者collapse都有expandwhile 循环遍历行,从单击行之后的那个开始,当它们到达同一级别的行时它们停止。这个逻辑应该适用于任何级别,而不仅仅是 0。此外,使用带有花哨选择器的逻辑,while循环可能会更干净nextUntil——在看到 Jules 回答之前,我并不熟悉那个 jQuery 方法——非常巧妙!

另外,为了使示例代码更简单,我将您的关卡类命名系统视为 HTML 数据属性,因此给定的行如下所示<tr data-level="0" id="10">:你可以.data用代码替换调用来解析你的类名。

var $rows = $('#mytable tr');

$rows.live('click', function() {
$(this).toggleClass('open');

if ($this.hasClass('open')){
    collapse($(this));
} else {
    expand($this);
}
}

function collapse ($row) {
    $row.removeClass('open');
var rowIndex = $rows.index($row);
var siblingOrAncestorRowFound = false;

while (!siblingOrAncestorRowFound){
    var $nextRow = $rows.eq(rowIndex + 1);
    if ($nextRow.level  > $row.level){
        $nextRow.hide().removeClass('open');
        rowIndex++;
    } else {
        siblingOrAncestorRowFound = true;
    }
}
}

function expand ($row) {
    $row.addClass('open')
var rowIndex = $rows.index($row);
var siblingOrAncestorRowFound = false;

while (!siblingOrAncestorRowFound){
    var $nextRow = $rows.eq(rowIndex + 1);
    if ($nextRow.level  > $row.level){

        // only show rows exactly one level below
        if ($nextRow.level == $row.level + 1){
            $nextRow.show();
        }

        rowIndex++;
    } else {
        siblingOrAncestorRowFound = true;
    }
}
}

(这未经测试 - 很抱歉,我必须打麻袋!)

于 2011-02-15T04:48:39.213 回答