Как сделать автоматическое изменение высоты предка на каждом уровне при добавлении / удалении вложенных потомков

0

В текущем проекте Im, работающем над я должен иметь возможность добавить несколько уровней сортируемых вложенных списков динамически с помощью jQuery. У меня есть вложенные сортируемые списки, работающие по желанию, но у меня возникают проблемы, когда следующие братья и сестры наследуют потомков предыдущих родительских братьев и сестер, как видно на этой скрипке

Визуально мне нужно, чтобы каждый элемент списка не перекрывал ни одного из потомков своих братьев и сестер, поэтому я подумал, что мне нужно установить высоту /margin-bottom на основе кумулятивных высот элементов-потомков.

Единственная попытка, которую я мог бы выполнить, - это:

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 уровня вложенных списков (то есть родитель вытолкнут из пути прямых детей, но не из-за детей детей.

Для справки подмножество поисковых запросов Google, которые я использовал, было:

  • "jquery, как сделать автоматическое изменение высоты предка на каждом уровне, когда вложенные дети добавлены/удалены"
  • "Изменение высоты родителя jQuery при добавлении/удалении вложенных детей"
  • "Высота контейнера списка jquery для увеличения по мере добавления элементов"
  • "jquery динамически меняет высоту div при добавлении ребенка"
  • "jquery cascading resize при динамическом добавлении/удалении дочернего элемента"
  • "Высота элемента списка jquery регулируется по высоте детей"

Помимо поиска в документации jQuery api, до сих пор я не нашел решения, я надеюсь, что другой набор глаз сможет указать на мою ошибку. Любая помощь приветствуется.

Обновление: мне повезло с рекурсивным подходом с этим кодом (обновленный скрипт), но, к сожалению, сейчас он устанавливает слишком большую часть поля:

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
Лучший ответ

Хорошо, у меня есть рабочая скрипка. Предложение @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;
    }
    
0

Из этого вопроса, который я задал, я считаю, что мы можем переделать код для вас. К сожалению, ваша скрипка только смутила меня, поэтому я не буду ее обновлять.

Каждый раз, когда вы добавляете элемент, вы должны изменить размер родителя и родительского родителя, используя maxHeight качестве возвращаемого этой функцией:

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

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

Я думаю, вам просто нужно отключить #builder для идентификатора родительского элемента.

В будущем, с JSfiddle, вы должны избегать включения посторонней информации и держать код простым. Там есть причины, что вы можете добавить кнопки с javascript, однако в jsfiddle было бы проще увидеть, только что вы использовали область HTML.

  • 0
    Итак, в случае с вашим примером кода я бы сделал что-то вроде: $('#builder').outerHeight(maxHeight); ? Я использую jQuery около недели, так что все еще чувствую эти вещи. Благодарю.
  • 0
    Также спасибо за предложение относительно упрощения скрипки, я просто не уверен, как сделать более простую скрипку. Я не могу использовать жестко запрограммированный html, потому что: 1. мои требования состоят в том, чтобы абсолютно все в #builder генерировалось динамически, 2. каждый вложенный список должен сортироваться друг с другом на своем уровне. Я сделал все возможное , чтобы упростить скрипку здесь , очевидно , комментирование , где мне нужна помощь , и где код установки начинается. Я хотел бы получить советы о том, как сделать более простой рабочий пример, который отвечает моим требованиям, спасибо.
Показать ещё 1 комментарий

Ещё вопросы

Сообщество Overcoder
Наверх
Меню