如何添加/删除嵌套子项时,如何使每个级别的祖先高度自动更改

时间:2014-04-23 18:45:49

标签: jquery css jquery-ui

在当前项目中,我需要能够使用jQuery动态添加多级可排序嵌套列表。我有嵌套的可排序列表按预期工作但我遇到的问题是,父母的下一个兄弟姐妹在视觉上重叠了以前父母兄弟姐妹的后代,如this fiddle所示

视觉上我需要每个列表项不与其兄弟姐妹的任何后代重叠,所以我的想法是我需要根据后代元素的累积高度设置高度/边距 - 底部。

我唯一可以尝试分类的工作是:

function resizeHeight(){
    var setToChildrenHeights = function(){
        var height = $(this).height();
        $(this).children().each(function(){
            height += $(this).outerHeight();
        });
        $(this).css('margin-bottom',height);
    }
    $("li").each(setToChildrenHeights);
}

问题在于,当我有3个级别的嵌套列表时,它不起作用(即父母被推出直接孩子的方式,但不会挡住孩子们的孩子。

作为参考,我使用的谷歌搜索子集是:

  • “jquery如何在添加/删除嵌套子项时在每个级别自动更改祖先高度”
  • “添加/删除嵌套子项时jquery父级高度更改”
  • “jquery列表容器高度随着项目添加而增加”
  • “jquery在添加子项时动态更改div的高度”
  • “当动态添加/删除子项时,jquery级联调整大小”
  • “jquery根据子高度调整列表元素高度”

除了搜索jQuery api文档之外,到目前为止我还没有找到解决方案,我希望另一组眼睛能够指出我的错误。任何帮助表示赞赏。

更新: 我有幸用这个代码(updated fiddle)采取递归方法,但不幸的是现在它设置了太多的利润底部:

function recursiveResize($parentElement){
    var numChild = $parentElement.children().length

    console.log('number of children = '+numChild);
    var parentHeight = $parentElement.height();
    if (numChild<1)
        return parentHeight;
    var height = 0;
    $parentElement.children().each(function(){
        height += recursiveResize($(this));
    });
    return parentHeight + height;    
}

//try2
function newResizeRecursive(){
    var $parentElements = $('li');

    $parentElements.each(function(){
        var height = $(this).height();
        var childrenHeights = recursiveResize($(this));
        var newmargin = childrenHeights - height +3
        console.log('new margin = '+newmargin);
        console.log('before '+$(this).css('margin-bottom'))
        $(this).css('margin-bottom', (newmargin>3 ? newmargin: 3))
        console.log('after '+$(this).css('margin-bottom'))
    });    
}

2 个答案:

答案 0 :(得分:0)

从我提出的this question开始,我相信我们可以为您重新编写代码。不幸的是,你的小提琴只能让我感到困惑,所以我不会更新它。

每次附加元素时,都应使用此函数返回的maxHeight调整父元素和父元素的大小:

var heightArray=$('#builder *').map(function(){
   return $(this).outerHeight();
}).get();

var maxHeight = Math.max.apply(Math, heightArray);

我认为您应该只需要为父元素的ID转出#builder

将来,使用JSfiddle,您应该避免包含无关的信息并保持代码简单。有些原因你可能想用javascript附加按钮,但是在jsfiddle中你会更容易看到你是否只使用了HTML区域。

答案 1 :(得分:0)

好的我有工作fiddle here。 @James G。的建议是一个很好的起点,但事实证明重新调整大小有两个问题:

  1. 为了让重新调整大小正常工作,我最终需要找到所有叶子节点然后遍历树,根据其后代的大小重新调整每个祖先的大小,如下所示:

    function resize(childId){
        //will find all the leafnodes
        var $leafnodes = findLeafNodes();
    
        //resize all ancestors of each leafnode
        $leafnodes.each(function(){
            resizebyID($(this).attr('id'));
        });
    }
    
    function resizebyID(childId){
        console.log('resize id='+childId);
        var $child = $('#'+childId);
        var $parent = $child.parent();
        var $grandparent = $parent.parent();
    
        //traverse each ansestor height in order
        $child.parentsUntil('#builder').each(function(){
            if ($(this).is('form')){}
            else{
                var heightsA = $(this).children().map(function(){
                   return $(this).outerHeight();
                }).get();
                var heightsum =0;
                for(var i=0; i<heightsA.length; i++)
                    heightsum += heightsA[i];
    
                $(this).css('margin-bottom',heightsum);
    
                console.log('ancestor:'+ $(this).attr('class')
                            +' height='+heightsum);
            }
        });
    }
    
    function findLeafNodes(){
        //try this, from #builder find the deepest child nodes 
        //and then resize each up the node from there:
        function innerMost( root ) {
            var $children = $( root ).children();
    
            while ( true ) {
                //set uniqueIDs so resize can work
                $children.each(function(){
                    $(this).uniqueId();
                })
                var $temp = $children.children();
                if($temp.length > 0) $children = $temp;
                else return $children;
            }
        }
    
        var $inner = innerMost($('#builder'));
        return $inner;
    }
    
  2. 我不仅需要在添加元素时重新调整大小,还需要在触发可排序事件时重新调整大小。所以我设置了可排序的对象,以便在触发事件时调用resize():

    function getSortableContainer(containerClass) {
        var $sortableContainer = $('<ul class="' + containerClass + '"></ul>');
        var sortOptions = {
            placeholder: "ui-state-highlight",
            opacity: 0.5,
            connectWith: '.' + containerClass,
            change: function (event, ui) {},
            stop: function (event, ui) {
                console.log("New " + containerClass + " position: " + ui.item.index());
                resize(childID);
            }
        };
    
        $sortableContainer.sortable(sortOptions);
        $sortableContainer.disableSelection();
        console.log("new " + containerClass + " added");
        return $sortableContainer;
    }