按高度均衡两个UL

时间:2011-08-02 15:07:52

标签: javascript jquery

我有一个案例,我提供了一个UL和一个未知数量的LI。我希望使用JS将LI分成2个UL(我正在使用jQuery)。我能够通过LI的数量均匀地分割UL,但是我想根据每个LI的高度将它分开,以便两个UL都接近相同的高度。

任何对此的帮助都会受到赞赏,我不觉得我已经开始采用我开始采用的方法了。

感谢。

编辑:我目前拥有的JS代码。 HTML只是一个直接的UL / LI,每个LI可以有不同的高度。

var $sections = $('div.subsection');

$sections.each(function(){
  var $section = $(this);

  var $list = $section.children('ul');
  var $items = $list.children('li');
  var itemCount = $items.size();
  var leftover = itemCount % 2;
  var itemsPerColumn = Math.floor(itemCount / 2);
  var $newList = $('<ul />');

  $items.each(function(){
    var $this = $(this);
    var index = $items.index($this);

    if (index >= (itemsPerColumn + leftover)) {
      $this.remove().appendTo($newList);
    }
  });

  $list.after($newList);

  _equalizeListHeights();

  function _equalizeListHeights(){
    var listHeight = $list.height();
    var newListHeight = $newList.height();

    if (listHeight > newListHeight){
      var $lastItem = $list.children('li:last');
      var lastItemHeight = $lastItem.height();

      if (listHeight - lastItemHeight > newListHeight + lastItemHeight){
        $lastItem.remove().prependTo($newList);
        _equalizeListHeights();
      }
    }
  }

});

4 个答案:

答案 0 :(得分:2)

你可以通过CSS来实现:

.double_column_list li {float: left; width: 50%;}

<ul class="double_column_list">
    <li>Awesome Stuff Awesome Stuff Awesome Stuff Awesome Stuff Awesome Stuff</li>
    <li>Awesome Stuff</li>
    <li>Awesome Stuff</li>
    <li>Awesome Stuff</li>
</ul>

要获得3列,请设置width: 33.333%,列width: 25%,依此类推。

当然,如果你继续将li的高度增加到li的其余部分无法匹配的点,那么这看起来会很糟糕。但是,这个问题也无法通过JS解决。

http://jsfiddle.net/rQJQb/

<强>更新 正如评论者所指出的,如果列表项没有按高度排序(即中间任何一个列表项的高度可能比前面的列表项更高/更小),则需要排序:http://jsfiddle.net/rQJQb/2/

答案 1 :(得分:1)

我想我至少可以在这里看到这种方法:

  1. 计算所有列表项(total)的总高度,并存储所有单独的高度
  2. 计算一个列表的高度(total / 2
  3. 确定一种算法,将heights的一组total / 2window.resize相加,但不得超过它。
  4. 将具有这些高度的元素放入第一个列表,然后将其余元素放入第二个
  5. 第3步是棘手的​​一点。它与Subset Sum Problem

    有关

    修改

    Here's a brute-force algorithm解决了您的问题。它不会在//Sum a jQuery wrapped array $.fn.sum = function() { var total = 0; this.each(function() { total += this; }); return total; }; //Mask elements with a bitmask $.fn.mask = function(mask) { return this.filter(function(i) { return (mask >> i) & 1; }) } //Get the sizes, and sneakily return a jQuery object var sizes = $('.first li').map(function() { return $(this).outerHeight() }); var total = sizes.sum(); var maxTotal = total / 2; var best = { total: 0, mask: 0 } for (var subsetMask = 1; subsetMask < (1 << sizes.length); subsetMask++) { //Sum all the heights in this subset var subsetTotal = sizes.mask(subsetMask).sum(); //New optimal solution? if (subsetTotal > best.total && subsetTotal <= maxTotal) { best = { total: subsetTotal, mask: subsetMask }; } } $('.first li').mask(best.mask).appendTo('.second'); 上运行,因为那会很愚蠢。如果要查看更改,请调整结果窗口的大小,然后按下运行。

    {{1}}

答案 2 :(得分:1)

您要解决的CS问题

您应该查看Backpack Problem。要“插入背包”的物品将是LI。每个LI的重量和值都等于其高度。背包容量应该是所有LI高度的一半。运行算法来解决背包问题,你的LI将被分为两组,如你所描述的那样高。

直观的解释

背包算法找到项目的子集,使得该值尽可能大,但重量不超过背包容量。但是我们每个LI的重量和价值都是它的高度,背包容量是所有LI组合总高度的一半。

基本上它给我们的是一组所有LI,使得高度尽可能高,不超过总高度的1/2。在你最终应该有两个相等高度的LI组的情况下,这将是其中一组。如果您最终应该使用两组具有不同高度的LI,则背包问题解决方案将返回具有较小高度的集合(并且剩余的,未选择的LI将是第二组)。

<强>解决方案

尝试使用此处使用的代码:http://rosettacode.org/wiki/Knapsack_problem/Bounded#JavaScript

或者如果你想自己动手(不推荐 - 为什么要这么麻烦?):http://en.wikipedia.org/wiki/Knapsack_problem#Unbounded_knapsack_problem

答案 3 :(得分:0)

$("ul.first li").each(function() {
    if ($("ul.first").outerHeight() > $("ul.second").outerHeight()) {
        $(this).appendTo($("ul.second"));
    }
});

使用此jQuery代码。