如何将一个很长的列变成多个较短的列?

时间:2009-07-08 19:03:08

标签: javascript jquery dom

这是一个挑战问题/问题。希望你发现它有意义。

场景:您在一个列中有一个很长的列表(不合理地长)。在多个较短的列中显示会更好。使用jQuery或其他工具,你做什么?

列表的格式如下:

<div class="toc">
    <dl>
        <dt>item 1</dt>
        <dd>related to 1</dd>
        <dt>item 2</dt>
        <dd>related to 2</dd>
        <dt>item 3</dt>
        <dd>related to 3</dd>
        <dt>item 4</dt>
        <dd>related to 4</dd>
        <dt>item 5</dt>
        <dd>related to 5</dd>
        <dt>item 6</dt>
        <dd>related to 6</dd>
        <dt>item 7</dt>
        <dd>related to 7</dd>
        <dt>item 8</dt>
        <dd>related to 8</dd>
        <dt>item 9</dt>
        <dd>related to 9</dd>
        <dt>item 10</dt>
        <dd>related to 10</dd>
    </dl>
</div>

警告:dd可能包含嵌套的dl,dt和&amp; DD的。

还要确保将相关项目保留在同一列中(即,如果dt 7为col x,则dd 7也应如此。)

这个问题的灵感来自于有点荒谬的Zend Framework manual

修改:请参阅下面的回答。

4 个答案:

答案 0 :(得分:1)

我会对$(“dt”)数组进行计数,然后如果它超过一定大小则注入一个闭合并打开然后使用样式将它们浮动到列中。

乔什

答案 1 :(得分:1)

忽略:

  

还要确保将相关项目保留在同一列中(即,如果dt 7为col x,则dd 7也应如此。)

一种可能的解决方案可能是column-count,例如:

http://pici.se/pictures/small/vekPcSkFE.png

然而,它是CSS 3的一部分所以browser support ......你知道。 :(

答案 2 :(得分:0)

我首先在json中写完整数据然后通过将此总和视为总行数来检查dt + dd +相关子项数量。

然后我会检查每列的预定义行数并将此json分成适当的部分。

最后,从这些部分我创建列而不会破坏相关项目。

思南。

答案 3 :(得分:0)

回答所以这个问题比第一次出现时更困难。

我最初的想法是,我会将列包裹在<table><tr><td></td></tr></table>中,然后在每个第n个 dd后输出</td><td>。简单吧?除非您无法真正输出这样的结束标记。最后,当您编写$('</td><td>').after('.toc > dl > dd')时,您将创建节点 - 即具有打开和关闭标记的节点。由于您必须创建节点,浏览器将忽略第一个结束标记。

好吧,让我们说你以某种方式解决了这个问题。你有什么迭代条件?我的第一次尝试是构建一个for循环。这看似合理。对于每个第n个父母dd,做你需要做的任何事情。但是,如何在jQuery中构造这些条件?你有少于,大于和平等。但是你没有大于或等于(&gt; =)或小于或等于(&lt; =),这是一个重要的区别。

您可以尝试这样的事情:

for (i = 0; i < len; i+=40) { // where 40 determines the # per col
  get elements i thru i+40;
  wrap this set and float left  
}

那么你将如何在jQuery中做到这一点?

// note that you must use > to prevent nested descendants from being selected
var len = jQuery('.toc > dl > dd').size()
for (i = 0; i < len; i+=40) {
  // this selector says give me the first 40 child elements 
  // whatever type of element they may be
  $('.toc > dl > *:gt('+i+'):lt('+(i+40)').wrapAll('<div style="float:left">');

  // however because we don't have >= and :gt won't accept negatives as an input
  // we must either do a special case for the first iteration 
  // or construct a different selector
  $('.toc > dl > *:eq('+i+')', ' + 
    '.toc > dl > *:gt('+i+'):lt('+(i+40)')
        .wrapAll('<div style="float:left">');
}

您也可以使用jQuery的add()方法将每个迭代的第一个元素添加到您的集合中,但您必须在选择中维护文档顺序,否则jQuery将重新排列集合,因此您必须首先执行此操作。

最终,for循环最初有意义,但它遇到挑战选择器的问题。当然,我们没有使用$('selector').each(function () { });构造,因为只有在我们输出独立的结束标记时才会有用。

那么我最终得到了什么? 最终答案:

$('.toc').after('<div id="new"></div>');
do {
    var curSet = $('.toc > dl > *:lt(40)')
           .appendTo('#new').wrapAll('<div style="float:left"></div>');
} while (curSet.size());

这种方法在旧的div之后附加一个新的div。然后迭代地抓取旧的前40个元素,并将它们包装在一个将向左浮动的div中,然后只要有剩余元素可以循环,并保持顺序,就将它们附加到新div。

在弄清楚之后并不是非常复杂,但是在整个问题中有一些问题我希望你觉得有趣。我做到了。

要完成使文档更有用的最终目标:

我添加了一些风格并使用dt作为切换器来显示dd。我还使用了一个简单的php代理包装器(5-10 LOC),因此我可以通过ajax调用引入任何给定的,所需的doc页面,而无需远程ajax警告。

我最后在单个可导航页面中加载了一个很好的小文档,该文档加载到&lt; 2秒(并使用ajax加载<1秒内的所​​有后续页面)而不是一个需要15-20秒才能加载每页的怪异页面!

问题解决了。更多愉快的东西,并且在10-15行javascript中有用(总计有重组,切换和ajax代码),&lt; 10行PHP,以及一些样式规则。

没有更慢的Zend文档和无休止的滚动。