1

我创建了一个 HTML 树视图,其行为类似于 Visual Studio 2012 中的解决方案资源管理器,其中树的每个节点都被拉伸以填充其容器的剩余空间,如下图所示:

Visual Studio 2012 解决方案资源管理器

为了实现这种行为,我正在使用 Javascript 创建一个无序列表来填充我的树 - DOM 结构看起来像这样:

<ul>
   <li>
      <input type="checkbox" id="node_xy" />
      <label for="node_xy" /> <!-- expand/collapse button -->
      <a href="javascript:nodeClickHandler();"> <!-- node text --> </a>
      <ul>
         <!-- subtree with li elements... -->
      </ul>
   </li>
</ul>

填充树后,我使用 Javascript (jQuery) 调整每个节点的宽度以填充其容器的剩余空间。容器宽度是固定的,但它是可滚动的(就像在 Visual Studio 中一样),所以每当用户展开或折叠树中的节点时,我都必须采取相同的宽度调整步骤,因为树的最大宽度可能会改变。代码的宽度调整部分如下所示:

updateLayout: function (containerWidth) {
    var self = $(this);
    self.find('.treeview a').css('width', ''); /* remove the width property for the next calculation */

    var maxAWidth = $('.treeview a').max(function () {
        return $(this).offset().left + $(this).outerWidth();
    });

    var targetWidth = containerWidth || $('.treeview').width();
    targetWidth = Math.max(targetWidth, maxAWidth);

    $('.treeview a').each(function () {
        var left = $(this).offset().left;
        $(this).outerWidth(targetWidth - left);
    });
}

它工作得很好,但是当树中有很多(几百或一千个)节点并且用户想要展开或折叠节点时,它会变得非常慢。在这些情况下,性能非常糟糕(每次展开/折叠计算 1-2 秒),因为该updateLayout方法遍历了我的树视图下的完整 DOM 树。我想知道这个“拉伸”问题是否有其他不使用这种遍历的解决方案?如果我能用某种纯 CSS 魔法解决这个问题会很好,但这似乎根本不可能......

更新:

标准 jQuery 优化(例如将查询结果提取到变量等)不起作用。例如以下代码并不比旧代码快:

    updateLayout: function (containerWidth) {
        var self = $(this);
        var treeviewLinks = self.find('.treeview a').css('width', '').get();

        var maxAWidth = -Infinity;
        for(var i = 0; i < treeviewLinks.length; i++) {
            var link = $(treeviewLinks[i]);
            if(link.offset().left + link.outerWidth() > maxAWidth)
                maxAWidth = link.offset().left + link.outerWidth();
        }
        var targetWidth = containerWidth || $('.treeview').width();
        targetWidth = Math.max(targetWidth, maxAWidth);

        for(var i = 0; i < treeviewLinks.length; i++) {
            var link = $(treeviewLinks[i]);
            link.outerWidth(targetWidth - link.offset().left);
        }
    }

updateLayout但是,我能够通过对树中的所有节点使用相同的宽度来加快这一步:

    updateLayout: function (containerWidth) {
        var treeviewLinks = $(this).find('.treeview a');
        $('#treeViewItemStyle').remove();

        var maxAWidth = treeviewLinks.max(function () {
            return $(this).offset().left + $(this).outerWidth();
        });

        var targetWidth = containerWidth || $('.treeview').width();
        targetWidth = Math.max(targetWidth, maxAWidth);
        $('<style id="treeViewItemStyle" type="text/css"> #treeview a { width: '
            + (targetWidth - 19) + 'px !important; } </style>')
        .appendTo('head');
    }

通过这种优化,updateLayout运行速度更快,但是由于相同的宽度,容器的最终宽度会比它需要的更大。我目前正在寻找其他解决方案以使其更好...

4

1 回答 1

0

首先,您使用了很多重复的查询,这是完全没有必要的,只需存储您的

$('.treeview a')

在变量中并重用它。除此之外,不要遍历整个 DOM,而是尝试只选择需要更改的元素,例如,只选择用户单击的最近元素的子列表。

于 2013-09-06T11:45:57.080 回答