В текущем проекте 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 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'))
});
}
Хорошо, у меня есть рабочая скрипка. Предложение @James G. было хорошим местом для начала, но оказалось, что было два вопроса с перераспределением вещей:
Чтобы получить правильный размер, мне пришлось найти все листовые узлы, а затем пересечь дерево, переустановив каждого предка на основе его потомков, например:
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;
}
Мне нужно было изменить размер не только тогда, когда были добавлены элементы, но также и при сортировке событий. Поэтому я настраиваю сортируемые объекты так, чтобы 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;
}
Из этого вопроса, который я задал, я считаю, что мы можем переделать код для вас. К сожалению, ваша скрипка только смутила меня, поэтому я не буду ее обновлять.
Каждый раз, когда вы добавляете элемент, вы должны изменить размер родителя и родительского родителя, используя maxHeight
качестве возвращаемого этой функцией:
var heightArray=$('#builder *').map(function(){
return $(this).outerHeight();
}).get();
var maxHeight = Math.max.apply(Math, heightArray);
Я думаю, вам просто нужно отключить #builder
для идентификатора родительского элемента.
В будущем, с JSfiddle, вы должны избегать включения посторонней информации и держать код простым. Там есть причины, что вы можете добавить кнопки с javascript, однако в jsfiddle было бы проще увидеть, только что вы использовали область HTML.
$('#builder').outerHeight(maxHeight);
? Я использую jQuery около недели, так что все еще чувствую эти вещи. Благодарю.