【问题标题】:How to turn a very long column into multiple shorter ones?如何将一个很长的列变成多个较短的列?
【发布时间】:2009-07-08 19:03:07
【问题描述】:

这是一个挑战问题/问题。希望你觉得它很有趣。

场景:您在单列中有一个很长的列表(长得不合理)。在多个较短的列中显示会更好。使用 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 和 dd。

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

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

编辑:答案见下文。

【问题讨论】:

  • 不知道别人是不是觉得禁忌,不过我欢迎HOWTO!
  • 我会用挑战标签标记它,因为你已经知道答案了。但那是我。
  • @seth,完成。不知道有一个。 :)

标签: javascript jquery dom


【解决方案1】:

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

乔什

【讨论】:

  • 关闭然后打开标签不起作用,但这也是我最初的方法。
【解决方案2】:

忽略:

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

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

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

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

【讨论】:

  • 好主意!但是,我可以看到它没有保持相关性条件。从挑战来看,如果顶级 dt 在一列中,则整个直接同级 dd 需要在同一列中 - 原因是我们要隐藏 dd 并通过单击 dt 将它们打开。
  • hmm ...我只是在想我们是否最终隐藏了相关的兄弟 dd。浏览器可能不会将这些元素包装到下一列 b/c 中,它们不会被显示。这里有可能......
【解决方案3】:

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

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

最后,我将在不破坏相关项目的情况下创建列。

思南。

【讨论】:

  • 我很好奇你的回答。你能把它冲掉一点吗?你到底在提议什么?也许是一些伪代码?
【解决方案4】:

Answer 所以这个问题比最初看起来要困难得多。

我最初的想法是我会将列包装在&lt;table&gt;&lt;tr&gt;&lt;td&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt; 中,然后在每第 n 个 parent dd 输出一个 &lt;/td&gt;&lt;td&gt; 之后。很简单,对吧?除了你不能真正输出这样的结束标签。最终,当您编写$('&lt;/td&gt;&lt;td&gt;').after('.toc &gt; dl &gt; dd') 时,您将创建节点 - 即具有打开和关闭标签 的节点。由于必须创建节点,浏览器将忽略第一个结束标记。

好吧,假设您以某种方式解决了这个问题。你的迭代条件是什么?我的第一次尝试是构建一个 for 循环。这似乎是合理的。对于每个第 n 个父母 dd,做任何你需要做的事情。但是,您如何在 jQuery 中构造这些条件?你有小于、大于和等于。但是您没有大于或等于 (>=) 或小于或等于 (

你可以试试这样的:

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 调用引入任何给定的所需文档页面,而无需远程 ajax 警告。

我最终在一个可导航的页面中得到了一个漂亮的小文档,该页面在 每页加载需要 15-20 秒!

问题解决了。在 10-15 行 javascript(包括重组、切换和 ajax 代码)、令人愉快和有用的东西。

不再有缓慢的 Zend 文档和无休止的滚动。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2021-03-18
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多