【问题标题】:How to make ancestor height auto change at each level as nested children added/deleted如何在添加/删除嵌套子项时在每个级别自动更改祖先高度
【发布时间】:2014-04-25 02:06:07
【问题描述】:

在我正在处理的当前项目中,我需要能够使用 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 cascading resize when child dynamic added/removed”
  • “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'))
    });    
}

【问题讨论】:

    标签: jquery css jquery-ui


    【解决方案1】:

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

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

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

    我认为您应该只需要将 #builder 切换为父元素的 id。

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

    【讨论】:

    • 好的,所以在你的代码示例中,我会这样做:$('#builder').outerHeight(maxHeight); ?我已经使用 jQuery 大约一个星期了,所以仍然对这些东西有感觉。谢谢。
    • 也感谢关于简化小提琴的建议,我只是不确定如何制作更简单的小提琴。我不能使用硬编码的 html,因为:1. 我的要求是绝对动态生成 #builder 中的所有内容,2. 每个嵌套列表必须可以在其自身级别与其他列表进行排序。我已尽我所能简化小提琴here,清楚地评论我需要帮助的地方以及设置代码的开始位置。我欢迎提供有关如何制作满足我要求的更简单的工作示例的指示,谢谢。
    【解决方案2】:

    好的,我有一个工作的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;
      }
      

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-05-25
      • 1970-01-01
      • 2022-08-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多