将Javascript应用于无序列表以实现多列效果

11

在(受支持的)CSS 中似乎没有简单的方法来做到这一点。我正在寻找一个JavaScript解决方案,最好是jQuery。

我有一个这样的无序列表:

<ul>
    <li>A</li>
    <li>B</li>
    <li>C</li>
    <li>D</li>
    <li>E</li>        
    ...etc
</ul>

我希望每个列有一个高度,例如四个项目,并且垂直填充,而不是像CSS浮动一样水平排列:

A     E
B     F
C
D

有没有什么理由必须使用 ul?在我看来,如果你有行和列,那就是表格内容,你需要一个表格。 - Jesse Dhillon
为了给您一些背景,这是一个链接列表。表格适用于表格数据,我同意。这是一种数据(链接)的列表,本质上就像来自表格的单列。那怎么能算作表格呢?通过使用列表,我将布局分离到了 JavaScript 而不是 HTML 中。如果 CSS/JavaScript 丢失,页面将有一个嵌套良好的列表而不是愚蠢的表格。 - Benbob
这是一个使用jquery的实时示例:jsfiddle.net/EebVF/5 使用此jquery插件:github.com/fzondlo/jquery-columns - newUserNameHere
7个回答

10
您需要使用CSS和jQuery的组合,但理论上非常简单。首先在HTML中呈现完整的单一列表,然后通过jQuery提供包装器并按需拆分列表。下面的函数就是这样做的。在实际使用脚本时,请确保使用比ul更具体的选择器,最好使用id

在此查看演示。

jQuery(function ($) {
  var size = 4,
      $ul  = $("ul"),
      $lis = $ul.children().filter(':gt(' + (size - 1) + ')'),
      loop = Math.ceil($lis.length / size),
      i    = 0;

  $ul.css('float', 'left').wrap("<div style='overflow: hidden'></div>");

  for (; i < loop; i = i + 1) {
    $ul = $("<ul />").css('float', 'left').append($lis.slice(i * size, (i * size) + size)).insertAfter($ul);
  }
});

虽然不完全符合我的需求,但这是一个不错的解决方案。比一些jQuery列插件要简单得多。+1 做得好。 - Benbob
@Keyo,这个列表是否应该动态填充? - Doug Neiner
不,但我只是不想改变我的现有CSS。我正在使用下拉菜单,suckerfish风格。将其分成3个列表将创建3个菜单链接。我猜把一堆<li>包在一个div里面是无效的?我的解决方案如下所示,但我承认它并不是最干净的。 - Benbob
1
太好了,我也需要按行而非列进行相同的操作,所以我调整了代码:http://jsfiddle.net/highrockmedia/8MQa8/ 谢谢! - Danny Englander

4

看这篇文章:

XHTML和CSS的一个小圣杯之一是产生一个单一的、语义逻辑有序的列表,可以包裹成垂直列。

我提前警告你。如果你想在多列中呈现列表,你必须做出妥协。你可以牺牲W3C网络标准并使用过时的标记,你可以接受不那么语义逻辑的标记,你可以容忍内容与表现的混合,你可以放弃浏览器兼容性,或者你可以使用带有属性且样式规则繁重的标记。每条路都要付出代价。

http://www.alistapart.com/articles/multicolumnlists/

“最佳”解决方案是主观的,但我倾向于使用任意类。

我在这里提问之前已经阅读了相关文章。那是一篇非常好的文章,我选择了JavaScript修复,因为即使它降级也不是一个很大的问题,而且我不想让HTML变得混乱。不幸的是,Alist没有提供任何JS解决方案。 - Benbob

2
道格的解决方案很好,如果你想把列表分成子列表。
相反,我选择在不改变DOM的情况下定位列表元素。这有点混乱,基本上是在每个元素上放置一个左边距,该左边距是列数乘以列宽。这将导致楼梯状布局,因此下一步是添加一些负上边距将每个元素提升到顶部。
基本上,这显示为网格。 我正在使用它来制作下拉菜单,所以它运行良好。 如果您需要每个列表项具有动态高度,请避免使用此功能。可以将col_height变量设置为最大项的高度,以使代码更加通用。
var col_max_height = 6; //Max Items per column
var col_width = 200; //Pixels
var col_height = 33; //Pixels
$('.header ul li ul').each(function() {
    $(this).find('li').each(function(index){
        column = parseInt(index/col_max_height);
        $(this).css('margin-left', column * col_width + 'px')
        if(column > 0) {
            $(this).css('margin-top', (index - (col_max_height * column)  + 1) * -col_height + 'px').addClass('col_'+column);
        }
    });
});

你如何设置使其在每个新列的顶部开始?现在,当下一列有例如2个<li>项时,它们将显示在底部而不是顶部。因此,基本上您必须从“margin-top:-300px”开始等等。但是你怎么做呢? - Meules

2
@Keyo,谢谢您的帮助回答。
只需要进行一些修改就可以在我的端上运行了。(公式已更改,或许对某个人有所帮助)
var col_max_item = 2; //Max Items per column
var col_width = $('.header ul li').css('width').replace("px", "");  //Pixels, get width from CSS
var col_height = $('.header ul li').css('height').replace("px", ""); //Pixels, get height from CSS  

    $('.header ul').each(function() { 
        $(this).find('li').each(function(index){ 
            column = parseInt(index/col_max_item);
            $(this).css('margin-left', column * col_width + 'px')
            if(column > 0 && (index / col_max_item) == column) {
                $(this).css('margin-top', (col_max_item * col_height * -1)  + 'px').addClass('col_'+column);
            }
        });
    });

2

1

只需要稍微不同的移动,下一列就会向上移动,而不是每个li。

var col_max_height = 6; //Max Items per column
var col_width = 120; //Pixels
var prevCol = 0; 
$('.header ul').each(function() {
    $(this).find('li').each(function(index){
    column = parseInt(index/col_max_height);
    $(this).css('margin-left', column * col_width + 'px')
        if(prevCol != column) {
            $(this).css('margin-top',  '-92px').addClass('col_'+column);
            prevCol = column;
        } else {
            $(this).css('margin-top',  '0px').addClass('col_'+column);
        }
    });
});

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接