Skip to content

Tree ​

Компонент иерархического дерева для отображения вложенных данных с раскрытием/сворачиванием, выбором, чекбоксами, drag & drop, фильтрацией, ленивой загрузкой, inline-редактированием и другими возможностями.

Basic ​

Кликните по стрелке узла-ветви, чтобы раскрыть или свернуть её.

Documents
Work
Reports.xlsx
Presentation.pptx
Personal
Resume.pdf
Budget.xlsx
Pictures
Vacation
beach.jpg
sunset.jpg
Screenshots
bug-report.png
Music
playlist.m3u
favorites.m3u
vue
<script setup>
import { VxTree } from 'veloxui'

const data = [
  {
    key: '1', label: 'Documents',
    children: [
      { key: '1-1', label: 'Work',
        children: [
          { key: '1-1-1', label: 'Reports.xlsx' },
          { key: '1-1-2', label: 'Presentation.pptx' },
        ],
      },
      { key: '1-2', label: 'Personal',
        children: [
          { key: '1-2-1', label: 'Resume.pdf' },
        ],
      },
    ],
  },
]
</script>

<template>
  <VxTree :data="data" />
</template>

Selection ​

Используйте v-model:selected, чтобы связать ключ выбранного узла. Включено по умолчанию.

Selected: none

Documents
Work
Reports.xlsx
Presentation.pptx
Personal
Resume.pdf
Budget.xlsx
Pictures
Vacation
beach.jpg
sunset.jpg
Screenshots
bug-report.png
Music
playlist.m3u
favorites.m3u
vue
<script setup>
import { ref } from 'vue'
const selectedKey = ref(null)
</script>

<template>
  <VxTree :data="data" v-model:selected="selectedKey" />
</template>

Multiple Selection ​

Включите multiple, чтобы выбирать несколько узлов. Удерживайте Ctrl (или Cmd на Mac) и кликайте, чтобы переключать отдельные узлы.

Selected: none

Documents
Work
Reports.xlsx
Presentation.pptx
Personal
Resume.pdf
Budget.xlsx
Pictures
Vacation
beach.jpg
sunset.jpg
Screenshots
bug-report.png
Music
playlist.m3u
favorites.m3u
vue
<script setup>
import { ref } from 'vue'
const selected = ref([])
</script>

<template>
  <VxTree :data="data" v-model:selected="selected" multiple default-expand-all />
</template>

Checkboxes ​

Добавьте чекбоксы через checkable. Родительские узлы показывают неопределённое состояние при частичном выборе.

Checked: none

Frontend
Vue
React
Angular
Backend
Node.js
Python
Go
Database
PostgreSQL
MySQL
MongoDB
vue
<script setup>
import { ref } from 'vue'
const checkedKeys = ref([])
</script>

<template>
  <VxTree :data="data" checkable v-model:checked="checkedKeys" default-expand-all />
</template>

Show Lines ​

Показывайте соединительные линии через show-line. Используйте line-style, чтобы выбрать solid, dashed или dotted.

Solid
src
components
Button.vue
Input.vue
Modal.vue
utils
helpers.ts
constants.ts
App.vue
main.ts
public
favicon.ico
package.json
tsconfig.json
Dashed
src
components
Button.vue
Input.vue
Modal.vue
utils
helpers.ts
constants.ts
App.vue
main.ts
public
favicon.ico
package.json
tsconfig.json
Dotted
src
components
Button.vue
Input.vue
Modal.vue
utils
helpers.ts
constants.ts
App.vue
main.ts
public
favicon.ico
package.json
tsconfig.json
vue
<template>
  <VxTree :data="data" show-line default-expand-all />
  <VxTree :data="data" show-line line-style="dashed" default-expand-all />
  <VxTree :data="data" show-line line-style="dotted" default-expand-all />
</template>

Filter with Highlight ​

Используйте filter-text, чтобы отфильтровать видимые узлы. Совпадающий текст подсвечивается автоматически. Дерево автоматически раскрывается, чтобы показать совпадающих потомков, и восстанавливает прежнее состояние при очистке фильтра.

Animals
Mammals
Dog
Cat
Elephant
Birds
Eagle
Parrot
Fish
Salmon
Tuna
Plants
Trees
Oak
Pine
Flowers
Rose
Tulip
vue
<script setup>
import { ref } from 'vue'
const filterText = ref('')
</script>

<template>
  <VxInput v-model="filterText" placeholder="Type to filter..." />
  <VxTree :data="data" :filter-text="filterText" default-expand-all />
</template>

Default Expand All ​

Используйте default-expand-all, чтобы раскрыть все ветви при монтировании.

Documents
Work
Reports.xlsx
Presentation.pptx
Personal
Resume.pdf
Budget.xlsx
Pictures
Vacation
beach.jpg
sunset.jpg
Screenshots
bug-report.png
Music
playlist.m3u
favorites.m3u

Accordion ​

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

Fruits
Apple
Banana
Orange
Vegetables
Carrot
Broccoli
Spinach
Grains
Rice
Wheat
vue
<template>
  <VxTree :data="data" accordion />
</template>

Node Icons ​

Используйте свойство icon в данных узла или настройте через слот #icon.

📁src
📄index.ts
🎨styles.css
📁utils
📄helpers.ts
📦package.json
🔒.gitignore
vue
<script setup>
const data = [
  {
    key: 'src', label: 'src', icon: '📁',
    children: [
      { key: 'index', label: 'index.ts', icon: '📄' },
      { key: 'styles', label: 'styles.css', icon: '🎨' },
    ],
  },
  { key: 'pkg', label: 'package.json', icon: '📦' },
]
</script>

<template>
  <VxTree :data="data" default-expand-all />
</template>

Используйте слот #icon для полного контроля:

vue
<template>
  <VxTree :data="data">
    <template #icon="{ node, expanded }">
      <MyIcon :name="node.children ? (expanded ? 'folder-open' : 'folder') : 'file'" />
    </template>
  </VxTree>
</template>

Children Count ​

Показывайте бейдж с количеством потомков через show-count. Настраивается через слот #count.

Components2
Basic3
Button
Input
Badge
Form2
Select
Checkbox
Utilities4
useClickOutside
useDebounce
useThrottle
useMediaQuery
vue
<template>
  <VxTree :data="data" show-count default-expand-all />
</template>

Node Actions ​

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

Workspace
Notes
Tasks
Calendar
Archive
Shared
vue
<template>
  <VxTree :data="data" default-expand-all>
    <template #actions="{ node }">
      <button @click="editNode(node)">Edit</button>
      <button @click="deleteNode(node)">Delete</button>
    </template>
  </VxTree>
</template>

Drag & Drop ​

Включите draggable, чтобы разрешить переупорядочивание узлов. Событие node-drop предоставляет dragNode, dropNode и position (before, inside или after), чтобы вы могли обновить данные.

Design System
Colors
Typography
Spacing
Components
Button
Input
Modal
Utilities
Helpers
Hooks
vue
<script setup>
import { ref } from 'vue'

const data = ref([...])

function onDrop(info) {
  console.log(info.dragNode.label, info.position, info.dropNode.label)
  // Handle data mutation here
}
</script>

<template>
  <VxTree :data="data" draggable @node-drop="onDrop" />
</template>

Настройте ручку перетаскивания через слот #drag-handle:

vue
<template>
  <VxTree :data="data" draggable>
    <template #drag-handle="{ node }">
      <MyGripIcon />
    </template>
  </VxTree>
</template>

Lazy Loading ​

Передайте функцию load, чтобы загружать потомков по требованию. Просто предоставьте данные и загрузчик — дерево сделает всё остальное:

  • Во время загрузки отображается индикатор
  • Пустые результаты автоматически помечают узел как лист (больше попыток загрузки не будет)
  • Ошибки показываются inline с кнопкой Retry
  • Уже загруженные узлы кэшируются — повторное раскрытие не приведёт к повторной загрузке
  • Используйте isLeaf: true на узлах, которые точно являются листьями, чтобы пропустить загрузку

Basic ​

Click the arrows to load children on demand. "Empty Folder" returns no results and becomes a leaf.

Folder A
Folder B
Empty Folder
readme.txt
vue
<script setup>
import { ref } from 'vue'

const data = ref([
  { key: 'folder-a', label: 'Folder A' },
  { key: 'folder-b', label: 'Folder B' },
  { key: 'empty', label: 'Empty Folder' },
  { key: 'readme', label: 'readme.txt', isLeaf: true },
])

async function load(node) {
  const res = await fetch(`/api/${node.key}/children`)
  return await res.json() // return TreeNodeData[]
}
</script>

<template>
  <VxTree :data="data" :load="load" />
</template>

Error Handling & Retry ​

Если load выбросит исключение, дерево покажет сообщение об ошибке с кнопкой повтора. Кликните по «Orders» ниже, чтобы увидеть состояние ошибки.

Users
Products
Orders
vue
<script setup>
async function load(node) {
  const res = await fetch(`/api/${node.key}/children`)
  if (!res.ok) throw new Error('Failed to fetch')
  return await res.json()
}
</script>

<template>
  <!-- Errors show inline with a Retry button -->
  <VxTree :data="data" :load="load" />
</template>

Editable Labels ​

Включите editable, чтобы разрешить переименование на месте. Двойной клик по подписи начинает редактирование. Нажмите Enter, чтобы сохранить, Escape, чтобы отменить. Обработайте событие node-edit, чтобы применить изменения.

Double-click a label to rename it

Project Alpha
Design
Development
Testing
Project Beta
Research
Prototype
vue
<script setup>
function onEdit({ node, newLabel, oldLabel }) {
  node.label = newLabel  // apply the change
}
</script>

<template>
  <VxTree :data="data" editable @node-edit="onEdit" />
</template>

Context Menu ​

Используйте слот #context-menu, чтобы добавить меню правого клика. Слот предоставляет node и close.

Right-click any node to see the context menu

Home
Dashboard
Analytics
Settings
Profile
Security
Help
vue
<template>
  <VxTree :data="data">
    <template #context-menu="{ node, close }">
      <div class="menu">
        <button @click="openNode(node); close()">Open</button>
        <button @click="renameNode(node); close()">Rename</button>
        <button @click="deleteNode(node); close()">Delete</button>
      </div>
    </template>
  </VxTree>
</template>

Striped Rows ​

Добавьте striped для чередования фонов строк, чтобы улучшить читаемость.

Category A
Item 1
Item 2
Item 3
Category B
Item 4
Item 5
Category C
Item 6
vue
<template>
  <VxTree :data="data" striped default-expand-all />
</template>

Virtual Scrolling ​

Для больших наборов данных включите virtual, чтобы отрисовывать только видимые узлы. Задайте virtual-height для высоты контейнера и item-height для высоты каждой строки.

50 categories × 20 items = 1,000 nodes

Category 1
Item 1-1
Item 1-2
Item 1-3
Item 1-4
Item 1-5
Item 1-6
Item 1-7
Item 1-8
Item 1-9
Item 1-10
Item 1-11
Item 1-12
Item 1-13
Item 1-14
Item 1-15
Item 1-16
Item 1-17
Item 1-18
Item 1-19
vue
<script setup>
// Generate 1,000 nodes
const data = Array.from({ length: 50 }, (_, i) => ({
  key: `cat-${i}`,
  label: `Category ${i + 1}`,
  children: Array.from({ length: 20 }, (_, j) => ({
    key: `cat-${i}-item-${j}`,
    label: `Item ${i + 1}-${j + 1}`,
    isLeaf: true,
  })),
}))
</script>

<template>
  <VxTree :data="data" virtual :virtual-height="300" :item-height="30" default-expand-all />
</template>

Disabled Nodes ​

Узлы с disabled: true нельзя выбрать или отметить.

Available Modules
Authentication
Dashboard
Locked Modules
Admin Panel
Billing

Custom Content ​

Используйте слот по умолчанию для полностью произвольной отрисовки узла. Получает node, expanded, selected и checkState.

📂 Inbox
📄 Starred
📄 Important
📄 Drafts
📂 Sent
📄 Today
📄 This Week
🗑️ Trash
⛔ Spam
vue
<template>
  <VxTree :data="data" default-expand-all>
    <template #default="{ node, expanded }">
      <span>{{ node.children ? (expanded ? '📂' : '📁') : '📄' }} {{ node.label }}</span>
    </template>
  </VxTree>
</template>

API ​

VxTree Props ​

PropTypeDefaultDescription
dataTreeNodeData[][]Данные дерева
selectedstring | number | null | arraynullВыбранный ключ(и) (v-model)
checked(string | number)[][]Отмеченные ключи (v-model)
expanded(string | number)[]—Раскрытые ключи (v-model)
default-expand-allbooleanfalseРаскрыть всё при монтировании
default-expanded-keys(string | number)[][]Ключи для раскрытия при монтировании
checkablebooleanfalseПоказать чекбоксы
selectablebooleantrueВключить выбор
multiplebooleanfalseРазрешить множественный выбор (Ctrl/Cmd+Click)
show-linebooleanfalseПоказать соединительные линии
line-style'solid' | 'dashed' | 'dotted''solid'Стиль линии
accordionbooleanfalseОдин узел на уровне
indentnumber24Отступ на уровень (px)
filter-textstring''Фильтр по подписи
highlight-filterbooleantrueПодсвечивать совпадения фильтра
draggablebooleanfalseВключить drag & drop
editablebooleanfalseВключить переименование двойным кликом
show-countbooleanfalseПоказать бейдж количества потомков
stripedbooleanfalseЧередующиеся фоны строк
load(node) => Promise<TreeNodeData[]>—Асинхронный загрузчик потомков
virtualbooleanfalseВключить виртуальную прокрутку
virtual-heightnumber400Высота виртуального контейнера (px)
item-heightnumber30Высота виртуального элемента (px)

TreeNodeData ​

PropertyTypeRequiredDescription
keystring | numberYesУникальный идентификатор
labelstringYesОтображаемый текст
childrenTreeNodeData[]NoДочерние узлы
disabledbooleanNoОтключить взаимодействие
isLeafbooleanNoПринудительный лист (пропустить ленивую загрузку)
iconstringNoИконка узла (emoji или текст)

Events ​

EventPayloadDescription
update:selectedkey | keys[]Выбор изменён
update:checkedkeys[]Состояние отметки изменено
update:expandedkeys[]Состояние раскрытия изменено
node-clicknodeКлик по узлу
node-expandnodeУзел раскрыт
node-collapsenodeУзел свёрнут
node-drop{ dragNode, dropNode, position }Узел сброшен (drag & drop)
node-drag-startnodeПеретаскивание начато
node-edit{ node, newLabel, oldLabel }Подпись отредактирована
node-context-menu{ node, event }Правый клик по узлу
node-loadednode, childrenЛенивая загрузка завершена

Slots ​

SlotPropsDescription
default{ node, expanded, selected, checkState }Пользовательское содержимое узла
icon{ node, expanded }Пользовательская иконка узла
actions{ node }Кнопки действий при наведении
drag-handle{ node }Пользовательская ручка перетаскивания
count{ node, count }Пользовательский бейдж количества
context-menu{ node, close }Контекстное меню правого клика
empty—Содержимое при пустых данных