Учимся создавать красивые деревья! (CTreeView)
Рубрика: Мелкие заметки на тему Yii
10 Окт. 2009Давайте сегодня поговорим о составлении древовидной структуры средствами встроенного в Yii класса CTreeView.
---Сегодня просматривал официальный форум фреймворка и в одном из своих постов нашел старый набросок кода. Его я кидал в качестве примера использования CTreeView для одного из пользователей. Я решил объединить этот код в некую заметку для читателей моего блога.
После прочтения этого урока вы научитесь делать такое:

Такое:

И даже такое:

Приступим...
Для того что бы отобразить нечто из того что я нарисовал выше — нам надо инициализировать виджет на странице одного из отображений вашего сайта. Примерно следующим образом:
$this->widget('CTreeView', array('data' => $my_data));
Параметру 'data' передается переменная $my_data, которая сообщяет виджиту о желаемой структуре дерева. Переменную $my_data мы можем определить сразу над вызовом виджета, либо передать с контроллера. Я для простоты объявляю сверху:
$my_data = array(
array(
'text' => 'Node 1',
'expanded' => true, // будет развернута ветка или нет (по умолчанию)
'children' => array(
array(
'text' => 'Node 1.1',
),
array(
'text' => 'Node 1.2',
),
array(
'text' => 'Node 1.3',
),
)
),
);
$this->widget('CTreeView', array('data' => $my_data));
Запускаем и смотрим. Должно было получится что то вроде этого:

Как вы понимаете вложенность массива не ограничивается. Вы можете вставлять детей используя параметр children. Если хотите что б ветка с детьми была по умолчанию свёрнута — используйте параметр expanded
Я немного усложнил код, чтобы вы смогли лучше понять что я хочу этим всем сказать:
$my_data = array(
array(
'text' => 'Node 1',
'expanded' => true, // будет развернута ветка или нет (по умолчанию)
'children' => array(
array(
'text' => 'Node 1.1',
'expanded' => false, // будет развернута ветка или нет (по умолчанию)
'children' => array(
array(
'text' => 'Node 1.1.1',
),
)
),
array(
'text' => 'Node 1.2',
'expanded' => true,
'children' => array(
array(
'text' => 'Node 1.2.1',
'expanded' => true,
'children' => array(
array(
'text' => 'Node 1.2.2.1',
'expanded' => true,
'children' => array(
array(
'text' => 'Node 1.2.2.1.1',
),
)
),
)
),
)
),
array(
'text' => 'Node 1.3',
'expanded' => true,
'children' => array(
array(
'text' => 'Node 1.3.1',
),
)
),
)
),
);
получилось:

Дальше — интереснее...
Сам класс включает в себя пару встроенных классов для изменения вида дерева. Они весьма приметивны и меняют только цвет рамок, но ничего не мешает использовать вам свой собственный класс!
Следующий пример отобразит нам дерево, с красными узлами:
$my_data = array(
array(
'text' => 'Node 1',
'children' => array(
array(
'text' => 'Node 1.1',
'children' => array(
array(
'text' => 'Node 1.1.1',
),
)
),
array(
'text' => 'Node 1.2',
'children' => array(
array(
'text' => 'Node 1.2.1',
),
)
),
)
),
);
$this->widget('CTreeView', array('data' => $my_data, 'htmlOptions' => array('class' => 'treeview-red')));

Как вы видите я использовал встроенный класс treeview-red. Вы можете попробовать все, из существующих в данный момент:
- treeview-gray
- treeview-red
- treeview-famfamfam
- filetree
- treeview-black
Давайте теперь попробуем использовать свой собственный класс, для оформления дерева, ведь это очень просто!
<style>
.my-class {
border: 3px solid #000;
background: #CCC;
padding: 5px;
width: 300px;
}
</style>
<?
$my_data = array(
array(
'text' => 'Node 1',
'children' => array(
array(
'text' => 'Node 1.1',
'children' => array(
array(
'text' => 'Node 1.1.1',
),
)
),
array(
'text' => 'Node 1.2',
'children' => array(
array(
'text' => 'Node 1.2.1',
),
)
),
)
),
);
$this->widget('CTreeView', array('data' => $my_data, 'htmlOptions' => array('class' => 'my-class')));

Посмотрите на структуру в которой вы получаете дерево. Поэкспериментируйте с CSS, и вы получите совершенно уникальное дерево!

Конец
Прочитав немного API по классу CTreeView, вы найдете еще кучу интересных вещей! Вроде параметра animated для плавного открытия узлов и др. :)
Вот и все!
Постоянно учитесь и делайте свои сайты лучше!
Если хотите опубликовать этот материал у себя - пожалуйста, разместите ссылку на страницу откуда вы его взяли.
- Уже достаточно давно мною была написана маленькая система управления сайтом для Творческого объединения Art of Art. Изначально все страницы сайта ... "artofart.ru - пишем cms на yii"
- Всем привет! Меня зовут Тимур и это мой небольшой Блог. Я очень рад что в интернете все больше находится ... "Hello World! Hello Yii.."
- Перед тем как начать подключать виджет RSS ленты я хотел бы немного освежить ваши знания по самой технологии.
RSS — ... "Компонент Rss ленты v1.0"

[guest] Ekstazi
Было сказано: Воскресенье, 11 Октябрь 2009
Я помню находил еще баг с невозможностью переопределить файл стилей. То есть брался и мой файл стилей и стандартный. И стандартный перекрывал мои стили. Но это было давно, может и исправили уже.

[guest] RSol
Было сказано: Воскресенье, 11 Октябрь 2009
Супер! Спасибо!
Я в свое время так намучался с этим. Теперь буду знать

[adm] zolter
Было сказано: Воскресенье, 11 Октябрь 2009
to Ekstazi
это не баг, сейчас точно так же. Т.е. вы должны переопределять те элементы которые вы хотите изменить. все остальные - Yii оставляет по умолчанию что б дерево не посыпалось. Ваши классы всегда на первом месте поэтому при переопределении не надо писать important и т.п.
если вам надо изменить в дереве тока плюсики - вы тока их и переопределяете в своем классе, при этом все остальные части дерева работают по старому стилю. очень удобно
to RSol
Пожалуйста :)

[guest] Ekstazi
Было сказано: Воскресенье, 11 Октябрь 2009
Хотел бы я с вами согласиться, но у меня в практике был случай, когда я подключил свой файл стилей к компоненту и ... пришлось писать !important чтоб все заработало как надо.

[adm] zolter
Было сказано: Воскресенье, 11 Октябрь 2009
Ну.. возможно вы и правы что раньше был такой баг. Я не застал. Сейчас все нормально, я пробовал когда урок делал ;)

itsme
Было сказано: Пятница, 18 Декабрь 2009
не нашел как сделать предраскрытой одну (конкретную) ветку
и 'collapsed'=>true у меня тоже не работает. код такой
$this->widget('CTreeView',array('data'=>($this->getDataFormatted()),
'animated'=>'fast',
'cssFile'=>'/css/treeview.css',
'htmlOptions'=>array('class'=>'treeview-red'),
'collapsed'=>false,
))

itsme
Было сказано: Пятница, 18 Декабрь 2009
'collapsed'=>true , конечно! от эксперимента осталась фальш

[guest] zolter
Было сказано: Пятница, 18 Декабрь 2009
Так этим парраметр 'expanded' занимается. В коде выше я его использовал что б разворачивать и сворачивать по умолчанию некоторые ветки.

[guest] Dart Anonimous
Было сказано: Четверг, 30 Декабрь 2010
Такой вопрос, а как удалить дерево? Есть дерево, произвольной вложенности. Есть ли в Yii штатное средство для удаления, какой-нибудь
MyModel::model()->findByPk(7)->deleteTree(array(
'columnName'=>'parentId'
));

[guest] zolter
Было сказано: Четверг, 30 Декабрь 2010
Так все зависит от того как вы деревья в базе храните и тп. Если для этого используете нестед-сетс тогда там есть функция рекурсивного удаления куска ветки. А что бы удалить конкретно дерево с экрана, а не данные - то только через обновление дива я думаю.

[guest] Dart Anonimous
Было сказано: Среда, 05 Январь 2011
Я имел ввиду конкретно такой способ хранения (с parent_id).
Можно удалить вот так:
'children'=>array(self::HAS_MANY, 'MyTree', 'parent_id'),// это у нас строчка показывающая отношение
protected function afterDelete() {
// После удаления комментария, удаляем все дочерние от него.
foreach ($this->children as $child)
$child->delete();
parent::afterDelete();
}
Будет много маленьких запросов. В Nested sets это наверное реализовано по-другому? Интересует вопрос нагрузки/быстродействия. Может кто-нибудь тестил уже (хотя врядли)).

[guest] Михаил
Было сказано: Понедельник, 14 Март 2011
никто случайно не использовал treeView для управления категориями?
т.е. возле каждого пункта размещены кнопки - редактировать, удалить, добавить подкатегорию и т.д.
Хотел написать скрипты на jQury, которые добавляли-бы к каждому узлу ссылки вида .....category/update&id=1, но столкнулся с проблемой, что в исходном коде нет html-кода узлов.
Т.е. я не могу задетектить их с помощью $('.treeview li').

[guest] Гость
Было сказано: Понедельник, 25 Апрель 2011
А не подскажите как сделать так что бы это меню отображалось в стиле таблицы, что бы четные и нечетные ряды были с разными бекграундами ??

[guest] Maxx
Было сказано: Понедельник, 25 Апрель 2011
Можно через jquery если не ошибаюсь покрасить все четные не четные после вывода. Так меньше гемора

[guest] Гость
Было сказано: Вторник, 26 Апрель 2011
Я про это сразу подумал и нечего не вышло, по тому что когда в jQuery селекторе указываешь дерево, то сразу все стили самого дерева пропадают :( дело в том что это дерево строиться с помощью jQuery и происходит конфликт, ну или я что то не так делаю :(

[guest] Pepe
Было сказано: Суббота, 03 Декабрь 2011
а можно сделать меню с помощью CTreeView горизонтальным

[guest] zolter
Было сказано: Четверг, 08 Декабрь 2011
Это обычный список по сути, на CSS обработайте его и сделайте горизонтальным.


