X   Сообщение сайта
(Сообщение закроется через 3 секунды)



 

Здравствуйте, гость (

| Вход | Регистрация )

Открыть тему
Тема закрыта
> Создание древовидного меню, как лучше сделать?
RussiaStudent
RussiaStudent
Topic Starter сообщение 20.8.2009, 23:41; Ответить: RussiaStudent
Сообщение #1


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

Заинтересовало, так как хочется сделать выпадающий список категорий с n-ным числом вложенности, которые можно добавлять динамически.
Это конечно не новость, во многих, да и почти во всех CMS есть возможность создания древовидного меню, ну или имеется модуль.
Я же загорелся данной идеей так как она содержит в себе парочку нюансов:

1) Нам нужно выстроить список n-ного вложения каждого родителя, тут не обойтись циклами for. Хотя можно попробовать while, но не кажется это не рентабельным
2) Не совсем понятно как хранить подобные выпадающие списки, сколько таблиц для этого понадобится и как же выстроить структуру таблиц?

Надеюсь на вашу помощь, знатоки. Натолкние меня в правильном направлении, а я постараюсь по мере своих ваозможностей организовать древовидное меню(выпадающий список)
0
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
НЕПЛОХОЙ
НЕПЛОХОЙ
сообщение 21.8.2009, 7:35; Ответить: НЕПЛОХОЙ
Сообщение #2


RussiaStudent, http://www.getinfo.ru/article610.html посмотрите вот эту статью, я сам ее не читал еще, но кажется то что надо


Поблагодарили: (0)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ZiTosS
ZiTosS
сообщение 21.8.2009, 10:51; Ответить: ZiTosS
Сообщение #3


Евгений, Читая подобное, думаешь "да разве подобное усложнение нужно в связках древовидного меню". Правые и левые ключи за которыми нужно следить + очень много воздействий на базу данных, так что просто можно её повесить. Так же не очень удобная выборка по ключу, делать ограничения.
Я тут на досуге подумал, всех лучше для создания древовидного меню подойдет одна таблица с примерным содержанием полей
id INT(11) auto_increment - идентификатор узла
id_parent INT(11) - родительский узел
title VARCHAR(255) - заголовок узла
.................

Вот что из себя представляют данные
1 | 0 | узел 1
2 | 0 | узел 2
3 | 0 | узел 3
4 | 0 | узел 4
5 | 1 | узел 1_1
6 | 1 | узел 1_2
7 | 2 | узел 2_1
8 | 2 | узел 2_2
9 | 4 | узел 4_1
10 | 4 | узел 4_2
11 | 4 | узел 4_3
12 | 4 | узел 4_4
13 | 10 | узел 4_2_1
14 | 10 | узел 4_2_2
15 | 11 | узел 4_3_1
16 | 11 | узел 4_3_2

Причем порядок следования узлов не важен, так как мы будем спускаться от 0 узла к максимальному. Все записи по уровням будут обработаны в последовательности.
Родительский узел 0 означает, что выбранный узел не имеет родителей.

Осталось написать функцию с помощью которой можно было бы осуществить постройку дерева и последующую обработку. Я думаю лучше всего бы было хранить связи в многомерном массиве на примере такого
array
(
   [id] => array
              (
                 [id] => id
                 [id_parent] => id_parent
                 [title] => title
                 [child] => array
                                (
                                   [id] => array
                                              (
                                                 [id] => id
                                                 [id_parent] => id_parent
                                                 [title] => title
                                                 [child] => array
                                                                (
                                                                   ...
                                                                )
                                               ),

                                   [id] => array
                                              (
                                                 [id] => id
                                                 [id_parent] => id_parent
                                                 [title] => title
                                                 [child] => array
                                                                (
                                                                   ...
                                                                )
                                               )
                                )  
              ),
.......................
)


Поблагодарили: (0)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
yury_mw
yury_mw
сообщение 21.8.2009, 10:58; Ответить: yury_mw
Сообщение #4


RussiaStudent,
я не большой спец по базам данных, но мне кажется, что наиболее простой и, соответственно, правильный ;) алгоритм, примерно, такой:
* делаем одну табличку с 2мя полями: [id узла] - [id родителя]
* если в id родителя - 0, то это корень дерева
* для построения потомков конкретного узла делаем выборку по заданному id родителя
* для построения всего дерева делаем цикл по всем id узлов

ну вот, пока писал, ZiTosS уже что-то похожее закодил ;)


Поблагодарили: (0)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
RussiaStudent
RussiaStudent
Topic Starter сообщение 21.8.2009, 11:30; Ответить: RussiaStudent
Сообщение #5


Спасибо всем за ответы. Структура понятна, красиво расписано.

Вообщем-то я тоже подумывал над одной таблице, так как для создания отдельных таблиц под каждую вложенность потребовало бы не малых затрат да и таблиц бы стало слишком много.
Постараюсь сегодня написать функцию обхода древовидного меню приведенного выше. Спасибо за наводку, действительно не так всё и сложно.

Интересует ещё всё же как легче написать обход дерева? Тут же нужен спуск по древу в каждой ветке. Читал когда-то про рекурсию - вызов самого себя. Может попробовать с помощью неё спуститься по дереву, как кто щитает правильный ли это подход. Или лучше написать обход с помощью while циклов?
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ZiTosS
ZiTosS
сообщение 21.8.2009, 23:56; Ответить: ZiTosS
Сообщение #6


RussiaStudent, рекурсия будет самое то. Только не забываем что рекурсивная функция либо должна возвращать массив детей, либо как-то его заносить во внутрь основного массива(тут можно массив по ссылке передавать)
С помощью while возможно не получится. Хотя можно, если составить сначала древо родителей, а потом его обходить и заносить. Но это сколько же лишнего кода. А вот в отношении рекрсии не так всё сложно. Она сама обойдет всё дерево, стоит только правильно функцию сформировать.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
RussiaStudent
RussiaStudent
Topic Starter сообщение 22.8.2009, 11:52; Ответить: RussiaStudent
Сообщение #7


ZiTosS, вот я думаю как же всё таки написать эту функцию рекурсии, воот что-то подумал и написал такое:
[php]function getChildMenu($massiv, $id_parent)
{
$resource=mysql_query("SELECT * FROM category WHERE id_parent={$id_parent}");
if(mysql_num_rows($resource)){
while($array=mysql_fetch_assoc($resource)){
$massiv[$array['id']]=$array;
// здесь вызов рекурсии, но как его организовать
}
}
}[/php]

Я тут подумал, как же заносить данные в массив, если в функции мы работаем с копией, и меняя её мы не меняем оригинал, на выходе мы опять же получем пустоту. И как же мне вызвать рекурсию?
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
ZiTosS
ZiTosS
сообщение 22.8.2009, 12:55; Ответить: ZiTosS
Сообщение #8


RussiaStudent,
как же заносить данные в массив, если в функции мы работаем с копией, и меняя её мы не меняем оригинал, на выходе мы опять же получаем пустоту

В языках программирование есть такое понятие, "Передача по ссылке" - что означает передача оригинала для работы с ним. Чтобы организовать в PHP передачу по ссылке достаточно перед переменной куда хотим передать ссылку поставить амперсанд ( & ):
[php]function nameFunction(&$ref, $copy)
{
// $ref - переданное по ссылке ( изменяя в функции, изменим и оригинал )
// $copy - копия ( изменяя в функции, оригинал не изменяется )
$ref = 1;
$copy = 1;
}

$param1 = $param2 = 0;

# вызываем функцию.
nameFunction($param1, $param2);

// Теперь $param1 = 1; $param2 = 0[/php]
И как же мне вызвать рекурсию?

Сначала тебе нужно создать подмассив детей, ключем к нему будет "child". А затем для него вызвать рекурсию. Типа этого:
[php].......................
$massiv[$array['id']]['child'] = array(); // создаём элемент массива для хранения детей
getChildMenu($massiv[$array['id']]['child'], $array['id_parent']); // вызываем рекурсию в качестве параметров (элемент(массив) хранения детей, родительский уровень(будем захватывать элементы, принадлежащие родительскому id))
.......................[/php]


Поблагодарили: (0)
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
RussiaStudent
RussiaStudent
Topic Starter сообщение 24.8.2009, 12:34; Ответить: RussiaStudent
Сообщение #9


ZiTosS, спасибо всё получилось. Вот написал де функции рекурсивных, одна собирает массив, а другая обрабатывает его и создаёт HTML-меню.

Функция создания древовидного массива:
[php]// Параметры: наш формирующийся массив $menu_child (по ссылке), наш текущий родительский уровень $id_parent (по умолчанию 0)
function getChildMenu(&$menu_child, $id_parent = 0) {
$resource=mysql_query("SELECT * FROM category WHERE id_parent={$id_parent}"); // вытаскиваем все меню(категории), которые соответствуют родительскому ID
// если записей не нуль
if(mysql_num_rows($resource) > 0) {
// обрабатываем в цикле все записи
while($array=mysql_fetch_array($resource)) {
$menu_child[$array['id']]=$array; // заносим в массив данные элемента(id, id_parent, title)
$menu_child[$array['id']]['child']=array(); // создаём раздел, куда будем детей добавлять
getChildMenu($con, $menu_child[$array['id']]['child'], $array['id']); // (рекурсивный вызов) в качестве параметров массив с ключем 'child' и текущий ID
}
}
}[/php]

Функция создания HTML (ul/li) меню:
[php]// Параметры: переменная, куда будем формировать контент $content (по ссылке), массив из которого формируем (должен быть в специально форме)
function printChildMenu(&$content, $menu) {
// начинаем обход массива $menu в цикле по записям
foreach($menu as $value) {
// если у текущего элемента нет детей
if(count($value['child'])==0)
$content.="<li><a href='./products_{$value['id']}.html'>{$value['title']}</a></li>"; // заносим элемент списка li
// если у текущего элемента есть дети
else {
$content.="<li><a href='./products_{$value['id']}.html'>{$value['title']}</a><ul>"; // заносим элемент списка li и открываем список детей
printChildMenu($content, $value['child']); // (рекурсивный вызов) обходим детей элемента для формирования списка
$content.="</ul></li>"; // заносим конец списка детей.
}
}
}[/php]

Замечание модератора:
Эта тема была закрыта автоматически ввиду отсутствия активности в ней на протяжении 100+ дней.
Если Вы считаете ее актуальной и хотите оставить сообщение, то воспользуйтесь кнопкой
или обратитесь к любому из модераторов.
Вернуться в начало страницы
 
Ответить с цитированием данного сообщения
Открыть тему
Тема закрыта
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0


Свернуть

> Похожие темы

  Тема Ответов Автор Просмотров Последний ответ
Открытая тема (нет новых ответов) как заслужить право на создание новой темы?
7 writer80 2089 12.3.2024, 22:54
автор: Lumex
Открытая тема (нет новых ответов) <Braga/> Создание Telegram-ботов, web-приложений, крипто-бирж, сайтов.
2 newbraga 1614 10.3.2024, 22:04
автор: newbraga
Открытая тема (нет новых ответов) СОЗДАНИЕ : / САЙтЫ / ЛЕНДЫ / БОТЫ ТГ / ВАЙТЫ / КРЕО / СОФТЫ / ДИЗАЙН [PHP, JS, HTML/CSS] и другое
5 CULA 3244 19.12.2023, 18:55
автор: CULA
Открытая тема (нет новых ответов) Создание и ведение аккаунтов в соцсетях ("В контакте"/Telegram)
Услуги от профессионального журналиста и SMM-менеджера
2 AvtorXXX 1636 13.11.2023, 23:47
автор: AvtorXXX
Открытая тема (нет новых ответов) Создание информационной площадки с доской объявлений
1 xweb 2030 16.1.2023, 16:25
автор: xweb


 



RSS Текстовая версия Сейчас: 19.3.2024, 18:01
Дизайн