我创建了一个 HTML 树视图,其行为类似于 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
运行速度更快,但是由于相同的宽度,容器的最终宽度会比它需要的更大。我目前正在寻找其他解决方案以使其更好...