3

我正在开发一个带有导航覆盖(节点和子节点)的响应式网站。导航应拆分为 4 列用于桌面视图或 2 列用于平板电脑视图。<ul />这是一个嵌套列表导航,因此围绕它构建了一个列。我的想法是,只需将导航写在 1 列中,然后使用 jquery 将其动态排列为 4 或 2 列。

html:

<!-- overlay -->
<nav class="overlay"> 
    <!-- ul for column -->
    <ul>
        <!-- nodes & subnodes -->
        <li><a href="#">node</a>
            <ul>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
            </ul>
        </li>
        <li><a href="#">node</a>
            <ul>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>                    
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
                <li><a href="#">subnode</a></li>
            </ul>
        </li>
        <li><a href="#">node</a> ...
    </ul>
</nav>

我写了这个函数:

    $.fn.arrangeObjects = function(wrapWith, maxCols) {

        this.each(function() {
            if ($(this).parent(wrapWith).length) $(this).unwrap();
        });

        this.parent().each(function() {
            var $el = $(this).children();
                amount = $el.length,
                wrapAmount = amount / maxCols;

            for (var i = 0; i < amount; i += wrapAmount) {
                $el.slice(i, i + wrapAmount).wrapAll('<'+ wrapWith +'/>');
            }
        });
    };

用于台式机:

$(".overlay > ul > li").arrangeObjects('ul', 4);

用于平板电脑:

$(".overlay > ul > li").arrangeObjects('ul', 2);

此解决方案将节点分成等份的列。不幸的是,这样看起来不太好:http:
//bern09.ch/notgood.png

我想要实现的是排列几乎相同的列高,如下所示:
http ://bern09.ch/good.png

我必须以某种方式尊重子节点的数量,但我真的不知道如何实现这一点。也许有人有很好的提示,我们将不胜感激。

4

2 回答 2

3

好的。我懂了。这有点棘手。昨天我开始计算每一列的高度,但我相信这种方法更灵活:

    this.parent().each(function () {
        var $subnodes       = $(this).children();

        // true will cause counter increment
        // false will cause counter decrement
        var inc     = true;
        var cols    = [];

        for (var i = 0; i < maxCols; i++) {
            cols.push($('<ul></ul>'));
            cols[i].appendTo($(this));    
        }

        function sortByHeight(a, b) {
            return $(a).height() > $(b).height() ? 0 : 1;
        }

        $subnodes = $subnodes.sort(sortByHeight);

        var i = 0;
        $subnodes.each(function () {
            // logic for left and right boundry
            if (i < 0 || i === maxCols) {
                inc = !inc;
                // this will cause node to be added once again to the same column
                inc ? i++ : i--;
            }

            cols[i].append($(this));

            inc ? i++ : i--;
        });
    });

这是一个概念。首先,我按所​​有节点的高度(从最高到最低)对所有节点进行排序,然后将它们附加到从左到右再到后的列(由 maxCols 指定)。它不如你的漂亮,不幸的是打破了 wrapAll 的使用(我非常喜欢它)。我已经在进行将使用threshold参数的小优化。当最短列和最长列之间的高度差大于阈值时,最长列的最后一个元素将移动到最短列。那么它应该看起来更自然。让我知道这是否是您正在寻找的。

于 2012-12-28T22:52:53.760 回答
3

首先也是最重要的 - 排序和分组应该尽可能在后端发生,在这种情况下就是这样。

当您在每列 UL 中对结果进行排序和分组后,您可以将 CSS3 列与旧版浏览器的 jQuery 后备一起使用,在此处解释

.overlay {
    -moz-column-count: 4;
    -moz-column-gap: 10px;
    -webkit-column-count: 4;
    -webkit-column-gap: 10px;
    column-count: 4;
    column-gap: 10px;
}

但是,如果您坚持使用 JavaScript 处理所有内容,则可以使用 Multi Column List jQuery 插件。
它似乎提供了您需要的解决方案。然而,它是在不久前编写的,因此您可能必须针对最新的 jQuery 版本修改其中的部分内容,并且可能会稍微满足您的需求。

于 2012-12-27T23:41:05.450 回答