Представляю @vue-dnd-kit/components: Готовые компоненты для быстрой разработки интерфейсов с перетаскиванием

от автора

Привет, Хабр! Недавно я представил вам Vue DnD Kit — библиотеку для создания интерфейсов с перетаскиванием в Vue 3. Сегодня хочу рассказать о новом пакете vue-dnd-kit/components, который значительно упрощает разработку сложных drag & drop интерфейсов.

Важно: Эта публикация — краткая новость о выходе пакета компонентов. Для полноценных примеров и подробной документации рекомендую перейти на официальный сайт документации.

⚠️ Статус проекта: Пакет находится в активной разработке (бета-версия). API может изменяться между минорными версиями. Не рекомендуется для продакшена до версии 1.0.0.

Что такое vue-dnd-kit/components?

vue-dnd-kit/components — это пакет готовых компонентов, построенных поверх основного пакета vue-dnd-kit/core. Он предоставляет готовые решения для типовых сценариев использования drag & drop, таких как:

  • 📋 Сортируемые таблицы с перетаскиванием строк и столбцов

  • 📊 Канбан-доски для управления задачами

  • 🌳 Древовидные структуры с неограниченной вложенностью

  • 🧩 Интерактивные дашборды с перетаскиваемыми виджетами

Ключевые особенности

1. CLI для быстрой установки компонентов

Одна из самых крутых фич — встроенный CLI, который работает по принципу shadcn/ui:

# Посмотреть доступные компоненты pnpm dlx @vue-dnd-kit/components list  # Добавить компонент в проект pnpm dlx @vue-dnd-kit/components add Table  # Добавить компонент в конкретную папку pnpm dlx @vue-dnd-kit/components add Kanban --dir src/shared/components 

Важно: CLI клонирует компоненты прямо в ваш проект, давая полный контроль над кодом и стилизацией. Вы можете свободно модифицировать, кастомизировать и адаптировать компоненты под свои нужды — это не зависимость, а ваш собственный код!

2. Минимальная стилизация

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

<template>   <Table     :rows="users"     :columns="columns"   >     <template #caption>Список пользователей</template>     <template #default="props">       <TableRow         v-for="(user, index) in users"         :key="user.id"         :row="user"         :row-index="index"         v-bind="props"       />     </template>   </Table> </template>  <style>   /* Ваши собственные стили */   .vue-dnd-table {     @apply w-full border-collapse;   }    .vue-dnd-table-row {     @apply hover:bg-gray-50 transition-colors;   } </style> 

3. Гибкая система слотов

Каждый компонент предоставляет множество слотов для кастомизации:

<template>   <Kanban     :columns="columns"     v-slot="{ columns }"   >     <KanbanColumn       v-for="(column, index) in columns"       :key="column.id"       :column="column"       :columns="columns"       :column-index="index"       :body-source="column.tasks"     >       <!-- Кастомный заголовок колонки -->       <template #header>         <div class="flex items-center gap-2">           <span class="font-semibold">{{ column.title }}</span>           <span class="text-sm text-gray-500">({{ column.tasks.length }})</span>         </div>       </template>        <!-- Кастомные карточки задач -->       <KanbanItem         v-for="(task, taskIndex) in column.tasks"         :key="task.id"         :item="task"         :items="column.tasks"         :item-index="taskIndex"       >         <div class="p-3 bg-white rounded-lg shadow-sm">           <h4 class="font-medium">{{ task.title }}</h4>           <p class="text-sm text-gray-600 mt-1">{{ task.description }}</p>         </div>       </KanbanItem>        <!-- Кастомный футер колонки -->       <template #footer>         <button class="w-full p-2 text-gray-500 hover:bg-gray-50 rounded">           + Добавить задачу         </button>       </template>     </KanbanColumn>   </Kanban> </template> 

Доступные компоненты

📋 Table — Сортируемые таблицы

Полнофункциональная таблица с возможностью перетаскивания строк и столбцов:

<script setup lang="ts">   import { ref } from 'vue';   import { Table, TableRow, type ITableColumn } from './components/Table';    interface IUser {     id: number;     name: string;     email: string;     role: string;   }    const users = ref<IUser[]>([     { id: 1, name: 'Иван Петров', email: 'ivan@example.com', role: 'Админ' },     {       id: 2,       name: 'Мария Сидорова',       email: 'maria@example.com',       role: 'Менеджер',     },     {       id: 3,       name: 'Алексей Козлов',       email: 'alex@example.com',       role: 'Разработчик',     },   ]);    const columns = ref<ITableColumn<IUser>[]>([     { label: 'ID', key: 'id' },     { label: 'Имя', key: 'name' },     { label: 'Email', key: 'email' },     { label: 'Роль', key: 'role' },   ]); </script>  <template>   <Table     :rows="users"     :columns="columns"   >     <template #caption>Список сотрудников</template>     <template #default="props">       <TableRow         v-for="(user, index) in users"         :key="user.id"         :row="user"         :row-index="index"         v-bind="props"       />     </template>   </Table> </template> 

Особенности:

  • Перетаскивание строк для изменения порядка

  • Перетаскивание столбцов для изменения их позиции

  • Кастомные заголовки столбцов через слоты

  • Поддержка статусов (success, processing, failed)

  • Визуальные индикаторы при перетаскивании

📊 Kanban — Канбан-доски

Гибкая канбан-доска для управления задачами и проектами:

<script setup lang="ts">   import { ref } from 'vue';   import { Kanban, KanbanColumn, KanbanItem } from './components/Kanban';    interface ITask {     id: number;     title: string;     description: string;     priority: 'low' | 'medium' | 'high';   }    interface IColumn {     id: number;     title: string;     tasks: ITask[];   }    const columns = ref<IColumn[]>([     {       id: 1,       title: 'К выполнению',       tasks: [         {           id: 1,           title: 'Изучить документацию',           description: 'Прочитать API docs',           priority: 'medium',         },         {           id: 2,           title: 'Написать тесты',           description: 'Покрыть код тестами',           priority: 'high',         },       ],     },     {       id: 2,       title: 'В работе',       tasks: [         {           id: 3,           title: 'Разработать UI',           description: 'Создать компоненты',           priority: 'high',         },       ],     },     {       id: 3,       title: 'Готово',       tasks: [         {           id: 4,           title: 'Настройка проекта',           description: 'Инициализация репозитория',           priority: 'low',         },       ],     },   ]); </script>  <template>   <Kanban     :columns="columns"     v-slot="{ columns }"   >     <KanbanColumn       v-for="(column, index) in columns"       :key="column.id"       :column="column"       :columns="columns"       :column-index="index"       :body-source="column.tasks"     >       <template #header>         <div class="flex items-center justify-between">           <span class="font-semibold">{{ column.title }}</span>           <span class="text-sm bg-gray-100 px-2 py-1 rounded-full">             {{ column.tasks.length }}           </span>         </div>       </template>        <KanbanItem         v-for="(task, taskIndex) in column.tasks"         :key="task.id"         :item="task"         :items="column.tasks"         :item-index="taskIndex"       >         <div           class="p-3 bg-white rounded-lg shadow-sm border-l-4"           :class="{             'border-red-500': task.priority === 'high',             'border-yellow-500': task.priority === 'medium',             'border-green-500': task.priority === 'low',           }"         >           <h4 class="font-medium text-sm">{{ task.title }}</h4>           <p class="text-xs text-gray-600 mt-1">{{ task.description }}</p>         </div>       </KanbanItem>     </KanbanColumn>   </Kanban> </template> 

Особенности:

  • Перетаскивание задач между колонками

  • Перетаскивание колонок для изменения порядка

  • Кастомные заголовки и футеры колонок

  • Гибкая система слотов для кастомизации

🌳 Tree — Древовидные структуры

Иерархические структуры с неограниченной вложенностью:

<script setup lang="ts">   import { ref } from 'vue';   import { Tree } from './components/Tree';    interface IFile {     id: number;     name: string;     type: 'file' | 'folder';     children?: IFile[];   }    const files = ref<IFile[]>([     {       id: 1,       name: 'Проект',       type: 'folder',       children: [         {           id: 2,           name: 'src',           type: 'folder',           children: [             { id: 3, name: 'main.ts', type: 'file' },             { id: 4, name: 'App.vue', type: 'file' },           ],         },         {           id: 5,           name: 'docs',           type: 'folder',           children: [{ id: 6, name: 'README.md', type: 'file' }],         },       ],     },   ]); </script>  <template>   <Tree     :data="files"     item-key="id"     nesting-key="children"     v-slot="{ item }"   >     <div class="flex items-center gap-2 py-1">       <span         class="text-lg"         :class="item.type === 'folder' ? 'text-blue-500' : 'text-gray-500'"       >         {{ item.type === 'folder' ? '📁' : '📄' }}       </span>       <span class="font-medium">{{ item.name }}</span>     </div>   </Tree> </template> 

Особенности:

  • Неограниченная вложенность

  • Разворачивание/сворачивание узлов

  • Перетаскивание элементов между уровнями

  • Визуальные индикаторы для элементов с детьми

  • Подсветка зон для сброса

🧩 Dashboard — Интерактивные дашборды

Гибкая система виджетов с перетаскиванием:

<script setup lang="ts">   import { ref } from 'vue';   import { Dashboard, DashboardItem } from './components/Dashboard';   import ChartCard from './components/Dashboard/Example/ChartCard.vue';   import StatCard from './components/Dashboard/Example/StatCard.vue';   import TaskList from './components/Dashboard/Example/TaskList.vue';    interface IDashboardItem {     id: number;     component: Component;   }    const dashboard = ref<IDashboardItem[]>([     { id: 1, component: ChartCard },     { id: 2, component: TaskList },     { id: 3, component: StatCard },   ]); </script>  <template>   <Dashboard     :data="dashboard"     class="dashboard"   >     <TransitionGroup       name="dashboard"       appear     >       <DashboardItem         v-for="(item, index) in dashboard"         :key="item.id"         :index="index"         :source="dashboard"         class="dashboard-item"       >         <component :is="item.component" />       </DashboardItem>     </TransitionGroup>   </Dashboard> </template>  <style>   .dashboard {     display: grid;     grid-template-columns: 1fr 1fr;     grid-template-rows: auto auto;     gap: 20px;     padding: 20px;   }    .dashboard-item {     border-radius: 12px;     background: white;     box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);     transition: all 0.3s ease;   }    .dashboard-move {     transition: all 0.3s ease;   } </style> 

Особенности:

  • CSS Grid для адаптивной раскладки

  • Плавные анимации при перетаскивании

  • Поддержка TransitionGroup

  • Кастомные виджеты через слоты

Как начать использовать

Установка

# npm npm install @vue-dnd-kit/components @vue-dnd-kit/core  # yarn yarn add @vue-dnd-kit/components @vue-dnd-kit/core  # pnpm pnpm add @vue-dnd-kit/components @vue-dnd-kit/core 

Быстрый старт с CLI

# Добавить таблицу pnpm dlx @vue-dnd-kit/components add Table  # Добавить канбан-доску pnpm dlx @vue-dnd-kit/components add Kanban  # Добавить дерево pnpm dlx @vue-dnd-kit/components add Tree  # Добавить дашборд pnpm dlx @vue-dnd-kit/components add Dashboard 

Подключение как плагин

import { createApp } from 'vue'; import App from './App.vue'; import VueDnDKitPlugin from '@vue-dnd-kit/core';  const app = createApp(App); app.use(VueDnDKitPlugin); app.mount('#app'); 

Преимущества перед другими решениями

1. Простота использования

  • CLI для быстрой установки компонентов

  • Интуитивный API на основе слотов

  • Минимальная конфигурация

2. Гибкость

  • Полный контроль над стилизацией

  • Кастомные слоты для любой кастомизации

  • Отсутствие привязки к конкретным UI-фреймворкам

3. Производительность

  • Оптимизированные компоненты

  • Минимальные перерисовки

  • Эффективная работа с большими списками

4. Доступность

  • Полная поддержка клавиатурной навигации

  • Совместимость со скринридерами

  • Семантическая разметка

Планы на будущее

Проект активно развивается! В разработке находятся дополнительные компоненты:

  • SortableList — простые сортируемые списки

  • FormBuilder — конструктор форм с перетаскиванием

  • Tabs — перетаскиваемые вкладки

  • FileExplorer — файловый менеджер

  • Grid — адаптивная сетка

Roadmap:

  • [x] Базовые drag & drop компоненты

  • [x] Table компонент

  • [x] Kanban доска

  • [x] Tree компонент

  • [ ] SortableList

  • [ ] FormBuilder

  • [ ] Dashboard

  • [ ] Tabs

  • [ ] FileExplorer

  • [ ] Grid

  • [ ] Тесты

  • [ ] Стабильный API (версия 1.0.0)

Заключение

vue-dnd-kit/components — это мощный инструмент для быстрой разработки сложных интерфейсов с перетаскиванием. Благодаря CLI, который работает по принципу shadcn/ui, гибкой системе слотов и минимальной стилизации, вы можете создавать профессиональные drag & drop интерфейсы за считанные минуты.

Ключевое преимущество: Компоненты клонируются в ваш проект, а не устанавливаются как зависимости. Это означает полную свободу в кастомизации и отсутствие привязки к конкретным версиям библиотеки.

Библиотека с открытым исходным кодом, активно развивается, и я буду рад любому вкладу от сообщества!

Полезные ссылки:

Буду рад вашим отзывам и предложениям в комментариях!


Теги: vue.js, drag-and-drop, dnd-kit, frontend-разработка, components, ui-library

Хабы: VueJS, Frontend-разработка


ссылка на оригинал статьи https://habr.com/ru/articles/920620/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *