Комментарии 44
toggleClass нужно заюзать в паре мест, вместо hasClass(...)? removeClass(...): addClass(...)
спасибо, сподвигли на дальнейшее узучение жквери. Все просто!
Вот на «чистом JS», проверил в FF3.0, IE6
<script type="text/javascript">
/*<![CDATA[*/
(function() {
var tree_init = function() {
this.clearWhitespace = function(element) {
var i, array = [];
for (i=0; i<element.childNodes.length; i++) {
if (element.childNodes[i].nodeType == 3) {
element.childNodes[i].nodeValue.match(/^[\s\r\n]+$/m) &&
array.push(element.childNodes[i]);
} else {
this.clearWhitespace(element.childNodes[i]);
}
}
for (i=0; i<array.length; i++) {
array[i].parentNode.removeChild(array[i]);
}
}
this.addMarker = function() {
var ul_item = this.tree.getElementsByTagName("ul");
for (var i=0; i<ul_item.length; i++) {
var li_item = ul_item[i].getElementsByTagName("li");
for (var j=0; j<li_item.length; j++) {
var child = li_item[j].getElementsByTagName("ul");
if (child.length > 0 && li_item[j].parentNode == ul_item[i]) {
var a_item = li_item[j].getElementsByTagName("a");
if (a_item.length > 0 && a_item[0].parentNode.parentNode == li_item[j]) {
a_item[0].innerHTML = '<em class="marker"></em>' + a_item[0].innerHTML;
}
}
}
}
}
this.addEvent = function() {
var span_item = this.tree.getElementsByTagName("span");
var thisCopy = this;
for (var i=0; i<span_item.length; i++) {
span_item[i].onclick = function() { thisCopy.click(this) };
}
}
this.setCurrent = function(a) {
if (this.current)
this.current.className =
this.current.className.replace("current", "");
this.current = a;
a.className += " current";
}
this.toggleClass = function(elem, classname) {
if (elem.className.indexOf(classname) != -1) {
elem.className = elem.className.replace(classname);
elem.className = elem.className.replace(" ", " ");
} else {
elem.className += " " + classname;
}
}
this.click = function(span) {
var subtree;
var a = span.firstChild;
var li = span.parentNode;
var ul = span.nextSibling;
var em = a.firstChild;
this.setCurrent(a);
if (li.nextSibling == null) {
li.hasChildNodes() && (subtree = li.childNodes[1]);
for (var i=0; i<subtree.childNodes.length; i++)
subtree.childNodes[i].className = "last";
}
if (ul && ul.nodeName.toLowerCase() == "ul")
ul.style.display = ul.offsetWidth > 0 ? "none" : "block";
if (em && em.nodeName.toLowerCase() == "em")
this.toggleClass(em, "open");
}
this.tree = document.getElementById('multi-derevo');
this.clearWhitespace(this.tree);
this.addMarker();
this.addEvent();
}
if (window.attachEvent) {
window.attachEvent("onload", tree_init);
} else {
window.addEventListener("load", tree_init, false);
}
})()
/*]]>*/
</script>
Вау! Мегатруд!
Кстати как бы сравнить скорости варианта jQuery и чистый. Это вроде можно сделать в Firebug, но я с ним знаком ровно столько сколько и с jQuery, т.е. маловато и не использовал его для профайлинга ни разу еще.
Кстати как бы сравнить скорости варианта jQuery и чистый. Это вроде можно сделать в Firebug, но я с ним знаком ровно столько сколько и с jQuery, т.е. маловато и не использовал его для профайлинга ни разу еще.
В функции на this.click можно заменить
хотя бы на
и стиль прописывать не для li.last, а для ul.last li
if (li.nextSibling == null) { li.hasChildNodes() && (subtree = li.childNodes[1]); for (var i=0; i<subtree.childNodes.length; i++) subtree.childNodes[i].className = "last"; }
хотя бы на
if (li.nextSibling == null && li.hasChildNodes() && (subtree = li.childNodes[1])) { subtree.className = "last"; }
и стиль прописывать не для li.last, а для ul.last li
Хотелось бы спросить у автора, какой-нибудь стресс-тест не проводили дереву? Просто в одном проекте приходится выводить порядка 1500-2000 узлов дерева. И хотелось бы узнать как оно по производительности.
Пробовал на ~270 элементах li.
Вложенность тоже может повлиять на работу.
Я думаю при таком количестве узлов необходимо дорабатывать код чтобы вложенные узлы загружались не сразу, а подкачивались при раскрытии, иначе я думаю будет слишком медленно.
Или есть реальная необходимость прямо все 1500-2000 узлов сразу вывести на страницу?
Или есть реальная необходимость прямо все 1500-2000 узлов сразу вывести на страницу?
Проблемы будут в любой реализации т.к. объем html кода будет ужасающим, а браузеру это все еще и обработать надо… У меня такая проблема с select на 3000 опций. 2 таких селекта на странице и про производительность можно забыть.
Вообще круто, спасибо автору.
Потестил пример, есть одно замечание к юзабилити дерева: кликая мышкой по родительскому нет возможности выделить элемент чтобы ветка не сворачивалась :)
Потестил пример, есть одно замечание к юзабилити дерева: кликая мышкой по родительскому нет возможности выделить элемент чтобы ветка не сворачивалась :)
НЛО прилетело и опубликовало эту надпись здесь
Я честно говоря даже не думал, что такое может понадобиться. Ведь если его делать, то придется усложнять скрипт и раскрытие делать по двойному клику, но пользователю это совсем не привычно тыкать по ссылке дважды.
Это конечно можно и доработать, давай еще предложения какие есть. Приделу же нет совершенства )
Это конечно можно и доработать, давай еще предложения какие есть. Приделу же нет совершенства )
Молодец, хорошо реализовал.
a.hasClass('current')?a.removeClass('current'):a.addClass('current');
замените на toggleClass
Чем $('#multi-derevo li:has(«ul»)').find('a:first')
лучше чем $('#multi-derevo li:has(«ul») a:first')?
замените на toggleClass
Чем $('#multi-derevo li:has(«ul»)').find('a:first')
лучше чем $('#multi-derevo li:has(«ul») a:first')?
Это мой первый скрипт на jQuery, я еще не понял до конца что как использовать. Делал по принципу «сделать любым способом — лишь бы работало».
Не хочу вас упрекать, но насколько мне известно и проверено — это совершенно разные объекты будут.
$('#multi-derevo li:has(«ul»)').find('a:first') — вернет мне все первые ссылки вложенные в li. В результате маркеур будет у всех ссылок для узлов с вложением,
а
$('#multi-derevo li:has(«ul») a:first') — вернет первую ссылку вложенную в li, и в результате маркер будет только у 1й первой ссылки вложенной в li.
Инфа find( expr ) , :first
Различия от использования видно на примерах в документации.
$('#multi-derevo li:has(«ul»)').find('a:first') — вернет мне все первые ссылки вложенные в li. В результате маркеур будет у всех ссылок для узлов с вложением,
а
$('#multi-derevo li:has(«ul») a:first') — вернет первую ссылку вложенную в li, и в результате маркер будет только у 1й первой ссылки вложенной в li.
Инфа find( expr ) , :first
Различия от использования видно на примерах в документации.
Видел я его, буквально сижу и смотрю. Скрипт там в несколько раз тяжелее, кому посложнее надо будет возьмет может его — от задачи зависит.
согласен. К тому же в большинстве случаев совершенно не нужен такой функционал. Да если и нужно что-то извращенное, то все-равно проще дописать (или найти готовую) функцию для этого, нежели впихивать библиотеку, потенциал которой будет использоваться на 10%. Плюс большое количество работающих скриптов на странице ведет к ужасающим лагам в IE, а иногда даже в FF.
Надоело уже как-то постоянно поддерживать баланс между размером кода, его производительностью и функциональностью…
Единственное, неплохо было бы кукисы реализовать…
Надоело уже как-то постоянно поддерживать баланс между размером кода, его производительностью и функциональностью…
Единственное, неплохо было бы кукисы реализовать…
На что кукисы поясни? Запоминать развернутый узел полагаю?
ага. Например пользователь развернул пару узлов, а потом перезагрузил страницу. Без кукисов узлы свернутся, а с кукисами останутся развернутыми. Мелочь, но приятно =)
Хорошая реализация дерева, но есть одно «но».
Чаще всего при клике на текст узла дерева нужно переходить на другую страницу (из одной категории в другую). В таком случае такой вариант реализации не подойдет т.к. по клику открывается поддерево узла. Для решения этой проблемы нужно будет переместить открытие узла на стрелку-открывалку, а саму ссылку оставить быть ссылкой на страницу. Но тут могут возникнуть проблемы.
Для своей реализации я использовал вот эту статью: javascript.ru/unsorted/tree + адаптировал под jQuery
Чаще всего при клике на текст узла дерева нужно переходить на другую страницу (из одной категории в другую). В таком случае такой вариант реализации не подойдет т.к. по клику открывается поддерево узла. Для решения этой проблемы нужно будет переместить открытие узла на стрелку-открывалку, а саму ссылку оставить быть ссылкой на страницу. Но тут могут возникнуть проблемы.
Для своей реализации я использовал вот эту статью: javascript.ru/unsorted/tree + адаптировал под jQuery
Кстати, данная реализация имеет один большой недостаток в js: onclick вешается на КАЖДЫЙ элемент дерева, что убьет любой браузер при большом количестве элементов.
Сейчас попробую адаптировать под это дерево более производительный вариант
Сейчас попробую адаптировать под это дерево более производительный вариант
> «данная реализация „
Какая данная? Что ты привел в своем предыдущем сообщении или моя?
Я на вопросах производительности не заморачивался, когда его делал. Оптимизация решений — это путь после получения первичного результата.
Какая данная? Что ты привел в своем предыдущем сообщении или моя?
Я на вопросах производительности не заморачивался, когда его делал. Оптимизация решений — это путь после получения первичного результата.
1.
2. js код для открытия-закрытия:
PS: код на работоспособность конкретно для этой реализации не проверял, но основная идея в том, что остается всего ОДИН onclick event на все дерево сколько бы там не было вложений.
PSS: думаю будет достаточно просто адаптировать эту функцию, если она все-таки не работает.
<div id="multi-derevo">заменяем на
<div id="multi-derevo" onclick="treeMenu(event)">
2. js код для открытия-закрытия:
function treeMenu(event) { event = event || window.event; var clickedElem = event.target || event.srcElement; // достаем узел на который нажали var node = jQuery(clickedElem.parentNode); // у зла нет поддерев? (узел-лист) if (!node.hasClass('marker')) return; // анимация node.children('ul').slideToggle(200); node.toggleClass('open'); }
PS: код на работоспособность конкретно для этой реализации не проверял, но основная идея в том, что остается всего ОДИН onclick event на все дерево сколько бы там не было вложений.
PSS: думаю будет достаточно просто адаптировать эту функцию, если она все-таки не работает.
насколько я понимаю через онклик можно вообще сделать без jQuery на чистом Javascript с почти такой же сложностью кода за исключением анимации (вот её не знаю как на чистом js делать).
изначально оно и было на чистом js, но поскольку jQuery в проекте и так подключена, то я адаптировал функцию под нее и добавил анимацию.
На чистом js есть здесь: javascript.ru/unsorted/tree
На чистом js есть здесь: javascript.ru/unsorted/tree
Думаю можно попробовать перевесить jQuery на #multi-derevo, что то подобное видел в предыдущей теме.
Я попробую.
Я попробую.
Ничего не мешает на открытие повесить и переход на страницу, однако я не заявляю это как готовый к использованию компонент. Чтобы сделать его пригодным для встраивания надо ним надо еще поработать.
Однажды я использовал подобный скрипт вместе с плагином jQuery Cookie. Подключение куков помогает запомнить положение элементов дерева после перезагрузки страницы. Мне кажется будет удобнее увидеть ветку, которую развернул, именно развёрнутой.
А вот демка плагина treeView, который также можно использовать вместе с куками.
А вот демка плагина treeView, который также можно использовать вместе с куками.
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Многоуровневое дерево с маркерами (HTML, CSS). Продолжение с jQuery