Ext.tree.Panel. Деревья
Для представления элементов в виде дерева используется класс Ext.tree.Panel
. Создадим простейшее дерево:
Ext.onReady(function(){ Ext.create('Ext.tree.Panel', { title: 'Страны СНГ', width: 200, height: 200, rootVisible: true, renderTo: Ext.getBody(), root: { text: 'Страны СНГ', expanded: true, children: [{ text: "Россия", children: [{ text: "Москва", leaf: true }, { text: "Санкт-Петербург", leaf: true }, { text: "Волгоград", leaf: true }], leaf: false, "expanded": true }, { text: "Украина", leaf: false }, { text: "Белоруссия" }] } }); });
В данном случае все узлы дерева задаются с помощью свойства root
, которое по сути представляет узел и может содержать дочерние
узлы в свойстве children
. Дочерние узлы в свою очередь также могут содержать другие узлы.
Узлы дерева
Узлы дерева реализуют ряд свойств, которые помогают настроить их поведение:
text
: заголовок узлаleaf
: указывает, имеет ли узел подузлы. Если свойство равноtrue
, то узел отображается как единичный узел (лист)expanded
: раскрыт ли узел (если свойство равноtrue
, то раскрыт)iconCls
: содержит в качестве значения класс CSS, который указывает на иконку узлаchildren
: содержит коллекцию подузлов дереваchecked
: отмечен ли узел. Если свойство равноtrue
, то рядом с заголовком появляется элемент checkbox, позволяющий отметить данный узел
В узлах у нас определено несколько свойств. Свойство text
показывает заголовок узла в дереве. Свойство leaf
указывает, как будет отображен узел - как единичный узел, если "leaf": true
, либо как поддерево, если "leaf": false
.
Еще одно использованное свойство expanded
показывает, будет ли узел раскрыт при загрузке дерева.
TreeStore и загрузка узлов из внешнего источника
Кроме статического задания схемы узлов дерева, мы можем использовать загрузку через внешнее хранилище, например, в формате json. Во-первых, создадим хранилище данных, из которого мы будем брать данные в дерево:
var store = Ext.create('Ext.data.TreeStore', { proxy:{ type: 'ajax', url: 'treeData.json' } });
В данном случае объект proxy содержит два свойства. Поскольку мы будем получать данные с сервера в формате json, то для свойства type
имеет значение ajax
. Свойство url
указывает на источник , который будет посылать приложению данные в json-формате. В данном
случае это файл json
. Но это также может быть и любое другое приложение, например, на php.
Теперь определим саму панель, в которую будет загружено дерево:
Ext.create('Ext.tree.Panel', { title: 'Страны СНГ', width: 200, height: 200, store: store, rootVisible: false, renderTo: Ext.getBody() });
Панель Ext.tree.Panel получает в свойстве store
ранее определенное хранилище. Свойство rootVisible: false
делает невидимым
корневой узел, в данном случае он нам не нужен.
Теперь перейдем к самим данным. Они у нас находятся в файле treeData.json, который имеет следующее содержание:
[{ "text": "Россия", "children": [{ "text": "Москва", "leaf": true }, { "text": "Санкт-Петербург", "leaf": true }, { "text": "Волгоград", "leaf": true }], "leaf": false, "expanded": true }, { "text": "Украина", "leaf": true }, { "text": "Белоруссия", "leaf": true }]
Объекты в формате json подчиняются определенным правилам: каждый объект заключается в фигурные скобки, а массив таких объектов - в квадратные.
Мы также в хранилище можем задать используем корневой узел, для этого используем rootVisible: true
и изменим определение хранилища следующим образом:
var store = Ext.create('Ext.data.TreeStore', { proxy:{ type: 'ajax', url: 'treeData.json' }, root: { text: 'Все страны', expanded: true } Ext.create('Ext.tree.Panel', { title: 'Страны СНГ', width: 200, height: 200, store: store, rootVisible: true, renderTo: Ext.getBody() }); });
Результат будет тем же, что и в первом случае.
Кроме того, мы можем не получать данные со стороны сервера, а закодировать их в самом хранилище, указав в корневом узле все подузлы:
var store1 = Ext.create('Ext.data.TreeStore', { root: { text:"Страны-участники", expanded: true, children: [{ text: "Россия", leaf: true },{ text: "Англия", leaf: true },{ text: "Франция", leaf: true }] } });
Сортировка дерева
Для установки у хранилища способа сортировки нам надо применить класс Ext.util.Sorter
через свойство
sorters
. Оно содержит определения сортировщиков, которые упорядочивают все узлы дерева. Сортировщик в качестве ключа
сортировки приминает свойство узла, которое указывается в свойстве property
.
Затем в свойстве direction
мы задаем порядок сортировки: прямой ('ASC') или обратный ('DESC').
Теперь изменим код хранилища store и дерева следующим образом:
Ext.onReady(function(){ var store = Ext.create('Ext.data.TreeStore', { root: { text: 'Страны СНГ', expanded: true, children: [{ text: "Россия", children: [{ text: "Москва", leaf: true }, { text: "Санкт-Петербург", leaf: true }, { text: "Волгоград", leaf: true }], leaf: false, "expanded": true }, { text: "Украина", leaf: false }, { text: "Белоруссия" }] }, sorters: [{ property: 'text', direction: 'ASC' }] }); Ext.create('Ext.tree.Panel', { title: 'Страны СНГ', width: 200, height: 200, rootVisible: false, store: store, renderTo: Ext.getBody() }); });
Таким образом, при загрузке все узлы будут отсортированы по свойству text
:
К примеру отсортируем узлы по свойству leaf
:
sorters: [{ property: 'leaf', direction: 'DESC' }]
Динамическая сортировка
Что если нам надо сортировать данные по сигналу от другого источника, например, по нажатию кнопки. В этом случае мы можем использовать
метод sort
класса Ext.data.TreeStore. Этот метод принимает параметры сортировки - свойство, по которому сортируем, и направление.
Добавим кнопку в приложение и определим обработчик нажатия:
var store = Ext.create('Ext.data.TreeStore', { root: { text: 'Страны СНГ', expanded: true, children: [{ text: "Россия", children: [{ text: "Москва", leaf: true }, { text: "Санкт-Петербург", leaf: true }, { text: "Волгоград", leaf: true }], leaf: false, "expanded": true }, { text: "Украина", leaf: false }, { text: "Белоруссия" }] } }); Ext.create('Ext.Button', { margin:'10 0 0 30', text: 'Сортировать', renderTo: Ext.getBody(), handler: function(){ store.sort('text', 'ASC'); } }); Ext.create('Ext.tree.Panel', { title: 'Страны СНГ', width: 200, height: 200, store: store, rootVisible: true, renderTo: Ext.getBody() });
Перенос узлов.
Ext JS 4 имеет встроенную поддержку drag-drop или ручного переноса узлов дерева как внутри самого дерева, так и между деревьями. За реализацию подобной функциональности отвечает специальный плагин Ext.tree.plugin.TreeViewDragDrop. А для его включения в панели дерева нам надо задействовать секцию viewConfig:
viewConfig: { plugins: { ptype: 'treeviewdragdrop' } }
Итак, определим два дерева, в которых мы сможем перетаскивать узлы:
Ext.onReady(function(){ var store1 = Ext.create('Ext.data.TreeStore', { root: { text:"Страны-участники", expanded: true, children: [{ text: "Россия", leaf: true },{ text: "Англия", leaf: true },{ text: "Франция", leaf: true }] } }); var tree1 = Ext.create('Ext.tree.Panel', { title: 'Антанта', store: store1, width: 200, height: 150, viewConfig: { plugins: { ptype: 'treeviewdragdrop' } } }); var store2 = Ext.create('Ext.data.TreeStore', { root: { text:"Страны-участники", expanded: true, children: [{ text: "Германия", leaf: true },{ text: "Австро-Венгрия", leaf: true },{ text: "Италия", leaf: true }] } }); var tree2 = Ext.create('Ext.tree.Panel', { title: 'Тройственный Союз', width: 200, height: 150, store: store2, viewConfig: { plugins: { ptype: 'treeviewdragdrop' } } }); Ext.create('Ext.panel.Panel', { title: 'Блоки накануне Первой мировой войны', width: 420, padding:10, height: 180, layout: { type: 'hbox', align: 'stretch' }, items: [tree1, tree2], renderTo: Ext.getBody() }); });
Мы можем также более детально настроить конфигурацию переноса узлов, воспользовавшись следующими опциями:
enableDrop: значение true позволяет принимать в данном дереве перетаскиваемые узлы
enableDrag: значение true позволяет переносить из данного дерева узлы (в пределах дерева или в другие деревья)
allowContainerDrop: значение true добавлять в данное дерево узлы
Так, если бы мы использовали в вышеприведенном примере эти опции, то они бы имели следующие значения:
viewConfig: { plugins: { ptype: 'treeviewdragdrop', enableDrop: true, enableDrag: true, allowContainerDrop: true } },
Добавление и удаление узлов дерева
Компонент Ext.panel.Panel представляет нам достаточную функциональность для добавления или удаления динамически новых узлов дерева.
В зависимости от задачи мы можем реализовать данную функциональность различными способами, используя методы компонента. Рассмотрим один из способов. Допустим, в левой части у нас определено дерево, а в правой части панель. На панели находятся кнопки для добавления и удаления. Чтобы добавить новый узел, надо сначала ввести текст узла в текстовое поле и нажать на соответствующую кнопку:
Ext.onReady(function(){ var menustore = Ext.create('Ext.data.TreeStore', { root: { text:"Языки программирования", expanded: true, children: [{ text: "C#", leaf: true },{ text: "C++", leaf: true },{ text: "Java", leaf: true }] } }); var tree = Ext.create('Ext.tree.Panel', { title: 'Языки программирования', store: menustore, width: 170, rootVisible: false, region: 'west' }); var centerPanel=Ext.create('Ext.panel.Panel', { title: 'Добавить/Удалить узел', region: 'center', bodyPadding:10, items:[{ xtype: 'textfield', id: 'txt', height: 20, },{ xtype: 'button', width:60, height: 20, text:'Добавить', handler: function() { // получаем введенное в текстовое поле значение var newNode=centerPanel.getComponent('txt').getValue(); // Используем метод appendChild для добавления нового объекта tree.getRootNode().appendChild({ text: newNode, leaf: true }); } },{ xtype: 'button', width:60, height: 20, margin: '0 0 0 20', text:'Удалить', handler: function() { // получаем выделенный узел для удаления var selectedNode=tree.getSelectionModel().getSelection()[0]; // если таковой имеется, то удаляем if(selectedNode) { selectedNode.remove(true); } } }] }); Ext.create('Ext.panel.Panel', { layout : 'border', width: 400, height: 180, padding:10, items : [tree, centerPanel], renderTo: Ext.getBody() }); });
Обработка выбора узла. Древовидное меню
При использовании дерева нередко возникает необходимость получить выделенный узел или произвести какие-то действия после выбора узла. В частности, на это строятся интерфейсы с помощью древовидного меню.
Обработка выбора узла дерева ложится на функцию itemclick
:
itemclick : function(this, record, item, index, e, options) {}
Эта функция принимает следующие параметры:
this
: объект, для которого производится выбор узлаrecord
: модель выбранного узла, через свойствоdata
мы можем получить данные узлаitem
: html-элементindex
: порядковый номер выбранного узла в коллекции узлов дереваe
: объект событияoptions
: дополнительные параметры, передаваемые в функцию
Поэтому создадим дерево в левой части, по нажатию на узлы которого в правой части будет отображаться выбранная опция:
Ext.onReady(function(){ var menustore = Ext.create('Ext.data.TreeStore', { root: { text:"Языки программирования", expanded: true, children: [{ text: "C#", leaf: true },{ text: "C++", leaf: true },{ text: "Java", leaf: true }] } }); var treemenu = Ext.create('Ext.tree.Panel', { title: 'Языки программирования', store: menustore, width: 170, rootVisible: false, region: 'west', listeners: { itemclick : function(tree, record, item, index, e, options) { var nodeText = record.data.text; centerPanel.update('<h3>Вы выбрали: '+nodeText+'</h3>'); } } }); var centerPanel=Ext.create('Ext.panel.Panel', { title: 'Выбранный язык', region: 'center' }); Ext.create('Ext.panel.Panel', { layout : 'border', width: 400, height: 180, padding:10, items : [treemenu, centerPanel], renderTo: Ext.getBody() }); });
Для компонента Ext.tree.Panel мы добавляем обработчик события itemclick
, которое возникает при нажатии на узел дерева.
Чтобы обработать это событие, в обработчик передается ряд параметров, из которых в данном случае мы используем только параметр record
.
Этот параметр представляет объект Ext.data.Model
и дает нам доступ к данным объекта, на котором было произведено нажатие.
Так, в строке var nodeText = record.data.text
мы получаем текст нажатого узла и выводим его в html правой панели.