Xpoint
   [напомнить пароль]

Древовидное меню

Метки: [без меток]
2007-10-01 07:37:54 [обр] gibz[досье]

Задача создать древовидное меню работающее следующим образом
допустим структура меню
1 Новости
1.1 Новости города
1.1.2 Новости администрации города
1.2 Новости в мире
2 Услуги
2.1 Ремонт
2.1.1 Квартир
2.1.2 Домов

и т.д.
хотелось бы чтобы при переходе вглубь раскрывалась текущая ветвь дерева, притом что корневые узлы дерева выводились тоже.
т.е. при нахождении в разделе
Новости администрации города меню выглядело бы так

Новости
  ->Новости города
    ->Новости администрации города
  ->Новости в мире
Услуги
 
Храниться дерево в базе данных в виде id,parent_id, я так думаю что необходимо вытащить всю структуру дерева в массив и работать с ним, не могу найти алгоритмов для подобного дерева, вывести все дерево непроблема, а вот сделать так как мне надо затык.

спустя 2 часа 13 минут [обр] Nuclon(4/19)[досье]

вот тут - рассмотрены несколько алгоритмов хранения и доступа к деревьям.
http://phpclub.ru/faq/wakka.php?wakka=Tree/FaqSelect

возможно, вам вместо id/parent_id более подойдет NestedSets ("вложенные множества") алгоритм. ИМХО.

спустя 2 минуты [обр] gibz[досье]
вообщем пока сделал по другому добавил в базу поле отвечающее за то открыт узел или нет, но при этом соответсвенно возросло количество запросов к бд по 1 запросу на каждый уровень погружения в дерево, понимаю что от этого растет наргузка на бд, но с другой стороны при не больших размерах дерева большой нагрузки на сервер это не вызовет.
спустя 1 минуту [обр] gibz[досье]
Nuclon[досье] по ссылке все полистал, вообщем пока получается что на операциях выборки id,pid все таки быстрее
спустя 26 минут [обр] Nuclon(4/19)[досье]
[[gibz]] в базу поле за открытый узел?
omg, а работу одновременно нескольких пользователей вы не рассматриваете? :)
спустя 1 час 6 минут [обр] gibz[досье]

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

         function tree($pid){
            $result=mysql_query("select * from tree where pid='$pid'");   
            if(mysql_num_rows($result)>0){
               print "<ul>\n";
               while($fetch=mysql_fetch_array($result)){
                  print "<li><a href=/".$fetch['path'].">$fetch[text]</a> | $fetch[id]\n";   
                  if($fetch['expanded']==1){tree($fetch['id']);}
               }
               print "</ul>\n";
            }
         }
         if(isset($_GET['query'])){
            $links=split("/",$_GET['query']);
            mysql_query("update tree set expanded=0");
            foreach($links as $link){
               print $link;
               mysql_query("update tree set expanded=1 where link='$link'");
            }
            //mysql_query("update tree set expanded=0 where path!='$_GET[query]'");
         }else{
            mysql_query("update tree set expanded=0");
         }
         tree(0);

т.е. человек который зайдет на сайт в любом случае увидит меню в таком виде каком и должен.

спустя 3 часа 48 минут [обр] Филипп Ткачев(20/112)[досье]
gibz[досье], так никогда не делают.
Рисуют просто ветвь от конца к началу.
Сначала выбирают id, потом определяют предка (pid), и так по восходящей к корню дерева. Все это складывают в массив, потом, на основании массива, рисуют дерево.
Можно сделать меню раскрывающимся, используя Ajax.
спустя 6 дней [обр] Эдуард Суров(147/264)[досье]

Лучше всего сделать так:

  1. Выбрать последовательно всех родителей текущего раздела. Отсюда знаем корневого родителя и непосредственного.
  2. Выбрать все корневые разделы.
  3. Выводим по очереди все корневые разделы. Напоровшись на корневого родителя и выведя его - начинаем выводить вглубь список родителей.
  4. Напоровшись на непосредственного родителя - отменяем его вывод и, если он не является также корневым родителем, выбираем список всех его братьев.
  5. Выводим список братьев. Напоровшись на непосредственного родителя, выводим вглубь текущий раздел.
  6. Завершаем вывод списка братьев непосредственного родителя.
  7. Завершаем вывод списка корневых разделов.

Parent id - не лучший способ для осуществления последовательной выборки родителей, так как не позволяет сделать это одним запросом. Используйте лучше nested sets, хотя для небольших деревьев я бы использовал materialized path.
Изменять в базе состояние дерева нельзя - база ведь одна, а пользователей много :) Информация о текущем узле должна браться из запроса (самый примитивный способ - передавать id текущего раздела через параметр в запросе).

Powered by POEM™ Engine Copyright © 2002-2005