Задать вопрос
ruskar
@ruskar
Conflict Intelligence Team

Проблемы с созданием иерархического дерева на jQuery?

Пытаюсь сделать для одного из своих проектов «иерархическое дерево» (по сути аналог jQuery Treeview, jsTree и тому подобных плагинов), в котором также задействован функционал drag & drop. Для задействования возможности drag & drop использую jQuery UI. Всё вроде получается, но застопорился на одном моменте.



Лирическое отступление: да, я знаю что это по сути написание велосипеда, и что можно не париться и взять один из распространённых плагинов, но для меня важно научиться делать разные фишки на jQuery с drag & drop, потому что он ещё много где нужен будет в моём проекте.



Значит что имеем. Есть ненумерованный список <ul></ul> элементы которого представляют собой категории. У категорий могут быть подкатегории, а у тех, в свою очередь, свои подкатегории и т.д. Если у категории есть подкатегории, то слева от неё отображается иконка «плюсик», нажав на который, произойдёт запрос на сервер и в ответ мы получим необходимый список подкатегорий, который автоматически вставится в виде подсписка, т.е. вот так:

<ul><br>
  <li class="categories close" id="cat1" rel="1">category A</li><br>
  <li class="categories open" id="cat2" rel="2">category B</li><br>
  <ul id="p2"><br>
    <li class="categories" id="cat4" rel="4">subcategory D</li><br>
    <li class="categories" id="cat5" rel="5">subcategory E</li><br>
    <li class="categories" id="cat6" rel="6">subcategory F</li><br>
  </ul><br>
  <li class="categories close" id="cat3" rel="3">category C</li><br>
</ul><br>




Лирическое отступление: да, я знаю что по правилам синтаксиса HTML подсписок <ul id=«p2»></ul> должен находится внутри родительского элемента <li></li>, но в таком случае вместе с категорией «category B» будет таскаться за курсором и весь подсписок подкатегорий, чего мы никак не хотим.



С помощью jQuery UI я делаю каждый элемент <li></li> «перетаскиваемым» (draggable), и одновременно «принимающим» (droppable).

Дальше я по задумке хочу сделать следующим образом: пользователь захватывает и начинает «таскать» категорию над списком других категорий; как только таскаемый им элемент оказывается над одной из категорий, происходит запрос на сервер, мы получаем и вставляем список подкатегорий. Делается это для того, чтобы облегчить жизнь пользователю: если пользователь хочет сделать категорию «category C» подразделом «subcategory F», то ему будет достаточно захватить «category C», задержать её над «category B» чтобы открылся список подкатегорий, после чего перетащить и отпустить над «subcategory F».



Всё вроде получается отлично, но есть одно НО, на котором я и застопорился: пользователь захватывает «category C» и держит её над «category B», тем самым заставляя открытся список подкатегорий; в момент появления списка подкатегорий, удерживаемый элемент «category C» уезжает вниз относительно курсора ровно на высоту всего подсписка категорий. Именно эту проблему мне не удаётся пока побороть.



Как я пытался решить эту проблему:



1) в момент вызова функции over (вызывается когда draggable-элемент находится над droppable-элементом и находится в состоянии готовности) пробовал запоминать позицию перетаскиваемого элемента в глобальных переменных вот так:

...<br>
over:function(event,ui) {<br>
  _cury = ui.position.top;<br>
  _curx = ui.position.left;<br>
  ...<br>
}<br>
...<br>




после этого запрашивать список подкатегорий и уже после их вставки заново присваивать перетаскиваемому элементу координаты:



...<br>
ui.position.top = _cury;<br>
ui.position.left = _curx;<br>
...<br>




В итоге не сработало.



2) я подумал, что возможно в момент появления подсписка и соответственно «отпрыгивания» перетаскиваемого элемента, он уходит из состояния готовности и вызывается функция out. Тогда я просто перенёс задание запомненных координат в функцию out:

...<br>
out:function(event,ui) {<br>
  ui.position.top = _cury;<br>
  ui.position.left = _curx;<br>
  ...<br>
}<br>
...<br>




Это тоже не сработало. Также пробовал использовать ui.offset вместо ui.position — тоже не помогло. Т.е. получение координат перетаскиваемого элемента происходит нормально, корректно. А вот попытка задать их обратно не приводит ни к каким результатам. Может кто подскажет решение?



Скачать полный код примера со всеми файлами и подробными комментариями.



Смотреть пример онлайн.
  • Вопрос задан
  • 3583 просмотра
Подписаться 3 Оценить Комментировать
Пригласить эксперта
Ответы на вопрос 3
@Thomas
Советую посмотреть как это сделано в последнем WordPress'e там похожее перетягивание в меню. Чужой код посмотреть иногда полезно бывает.
Ответ написан
Комментировать
Лирическое отступление: да, я знаю что по правилам синтаксиса HTML подсписок <ul id=«p2»></ul> должен находится внутри родительского элемента <li></li>, но в таком случае вместе с категорией «category B» будет таскаться за курсором и весь подсписок подкатегорий, чего мы никак не хотим.

Для такого случая берем «category B» в отдельный элемент, например <span>

Пример у меня не работает. Было бы неплохо выложить куда-нибудь
Ответ написан
nikitammf
@nikitammf
Дело в том, что при draggable jqueryui использует position: relative, поэтому после открытия уровня необходимо к top добавлять высоту открытого уровня.
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы