---
title: "DevTools"
description: "Вкладка Vue DnD Kit во Vue DevTools и Nuxt DevTools — живая мини-карта, джойстик, который перетаскивает по-настоящему, правка опций на лету и журнал каждого драга."
canonical_url: "https://zizigy.github.io/vue-dnd-kit/ru/docs/guides/devtools"
---

> Index of every page on this site: [llms.txt](https://zizigy.github.io/vue-dnd-kit/llms.txt)

`@vue-dnd-kit/devtools` добавляет вкладку **Vue DnD Kit** во Vue DevTools (`vite-plugin-vue-devtools`)
и в Nuxt DevTools. Она показывает каждый список, дерево и цель на странице на живой мини-карте,
перетаскивает любой элемент джойстиком, правит опции, пока приложение работает, и записывает, что
сделал каждый драг. Она работает только в разработке: ничего из неё не попадает в
продакшен-сборку.

Вкладка — отдельная страница, которую раздаёт ваш dev-сервер рядом с приложением, поэтому внутри
этой документации она работать не может. Настройка — три шага.

## Установка

### 1. Добавьте пакеты

```bash
npm i -D @vue-dnd-kit/devtools @vue-dnd-kit/actions
```

`@vue-dnd-kit/actions` — peer-зависимость: перемещения вкладки идут через неё. npm 7+ и pnpm
устанавливают её сами; с Yarn 1 добавьте её.

### 2. Добавьте плагин

<code-group>

```ts [vite.config.ts]
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import vueDevTools from 'vite-plugin-vue-devtools';
import { vueDnDKitDevtools } from '@vue-dnd-kit/devtools/vite';

export default defineConfig({
  // Next to the Vue DevTools plugin: the tab joins its sidebar.
  plugins: [vueDevTools(), vueDnDKitDevtools(), vue()],
});
```

```ts [nuxt.config.ts]
export default defineNuxtConfig({
  // With @vue-dnd-kit/devtools installed, the tab appears in development.
  modules: ['@vue-dnd-kit/nuxt'],
});
```

</code-group>

С Vite плагин делает на dev-сервере (`vite serve`) три вещи: раздаёт вкладку по адресу
`/__vue-dnd-kit-devtools/` (внутри вашего `base`), добавляет её во Vue DevTools и заставляет
страницу сообщать ей о себе до старта приложения. `app.use()` не нужен, а сборки не
затрагиваются.

С Nuxt модуль `@vue-dnd-kit/nuxt` находит пакет, раздаёт вкладку, добавляет её в Nuxt DevTools и
устанавливает сторону страницы клиентским плагином. `vueDndKit: { devtools: false }` это
отключает.

### 3. Запустите приложение в режиме разработки

Запустите dev-сервер как обычно (`vite`, `nuxt dev`) и откройте приложение: вкладка готова. В ней
отображается каждый провайдер страницы, в каком бы приложении он ни рендерился.

### Без плагинов

Для собственного dev-сервера или страницы, которую Vite раздаёт не из `index.html` (SSR-сетапы),
установите сторону страницы сами:

```ts [main.ts]
import { createApp } from 'vue';
import { DnDDevtools } from '@vue-dnd-kit/devtools';
import App from './App.vue';

const app = createApp(App);
app.use(DnDDevtools); // before mount: providers set up earlier aren't seen
app.mount('#app');
```

Или импортируйте `@vue-dnd-kit/devtools/auto` первым во входном файле. Используйте
`vueDnDKitDevtools({ inject: false })`, когда плагин должен раздавать вкладку, а сторону
страницы вы устанавливаете сами; `serveTab()` из `@vue-dnd-kit/devtools/vite` — middleware,
которое раздаёт вкладку.

<note>

В продакшен-сборке `app.use(DnDDevtools)` и импорт `auto` сжимаются почти в ничто: каждая точка
входа сначала проверяет `process.env.NODE_ENV`, а бандлеры выбрасывают остальное. На сервере они
ничего не делают.

</note>

## Как открыть

- **Vue DevTools**: <kbd value="Alt">



</kbd>

 + <kbd value="Shift">



</kbd>

 + <kbd value="D">



</kbd>

 или кнопка Vue
внизу страницы, затем вкладка **Vue DnD Kit**.
- **Nuxt DevTools**: <kbd value="Alt">



</kbd>

 + <kbd value="Shift">



</kbd>

 + <kbd value="D">



</kbd>

 или кнопка Nuxt,
затем **Vue DnD Kit** (в боковой панели или в её меню переполнения).
- **Отдельное окно**: откройте `http://localhost:5173/__vue-dnd-kit-devtools/` на своём
dev-сервере или нажмите кнопку ⧉ вкладки. Удобно на втором экране. Если открыто несколько
страниц, селект сверху выбирает, за какой следить.

<warning>

Держите вкладку в отдельном окне, а не в фоновой вкладке браузера того же окна: страница должна
оставаться видимой, а скрытая страница отменяет драги.

</warning>

## Вкладка вкратце

<table>
<thead>
  <tr>
    <th>
      Часть
    </th>
    
    <th>
      Что в ней
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Верхняя панель
    </td>
    
    <td>
      Что драг делает прямо сейчас (<code>
        dragging card-3 → done (accepts)
      </code>
      
      ), отслеживаемая страница, <strong>
        ⌖ Pick
      </strong>
      
      , число изменённых опций со сбросом, ⧉ (отдельное окно) и тема.
    </td>
  </tr>
  
  <tr>
    <td>
      Слева: реестр
    </td>
    
    <td>
      Каждый провайдер в виде дерева: его списки, деревья, цели и перетаскиваемые элементы. <strong>
        ☰
      </strong>
      
       показывает или скрывает его.
    </td>
  </tr>
  
  <tr>
    <td>
      В центре: <strong>
        Map
      </strong>
      
       и <strong>
        Log
      </strong>
    </td>
    
    <td>
      Живая мини-карта страницы или журнал драгов.
    </td>
  </tr>
  
  <tr>
    <td>
      Справа: <strong>
        Drive
      </strong>
      
      , <strong>
        Options
      </strong>
      
      , <strong>
        State
      </strong>
    </td>
    
    <td>
      Джойстик и кнопки перемещения, опции выбранного узла и то, что о нём знает провайдер.
    </td>
  </tr>
</tbody>
</table>

Выберите узел в реестре или элемент на карте, и правая часть следует за ним.

## Мини-карта

Живая карточка на каждый список, дерево и цель, с копиями их элементов там, где они есть, — те же
клоны, которые показал бы оверлей, со стилями страницы. Во время драга она отмечает:

- списки и цели, которые **принимают** драг (синие) или **отклоняют** его (красные);
- плейсхолдер и цель под указателем;
- указатель, блок оверлея и линию вставки списков с `placeholder: 'indicator'`.

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

## Drive: джойстик

Выберите элемент — на карте, в реестре или через **⌖ Pick**, который перехватывает следующее
нажатие на перетаскиваемый элемент страницы, не давая ему сработать, — и толкните рукоятку
джойстика. Элемент берётся и движется в ту сторону, тем быстрее, чем дальше рукоятка от центра.
Отпустите — и он остановится; **Drop** и **Cancel** завершают драг.

Это настоящий драг указателем от сенсора по имени `devtools`, сделанный на публичном
[API сенсоров](https://zizigy.github.io/docs/guides/sensors#a-sensor-of-your-own): списки сортируются под ним, контейнеры
прокручиваются у краёв, а `onBeforeDrop` и `onDrop` выполняются, как для любого драга.
Отключённые элементы не берутся. Перетаскиванием с клавиатуры, начатым на странице, тоже можно
управлять.

Элементы сортируемых списков получают ещё и кнопки: вверх, вниз, в начало, в конец, в другой
список группы. Каждая — одно перетаскивание с клавиатуры через
[`moveItem`](https://zizigy.github.io/docs/guides/sensors#programmatic-drags). Под джойстиком — крупная копия того, что
показывает оверлей.

<table>
<thead>
  <tr>
    <th>
      Клавиша во вкладке
    </th>
    
    <th>
      Действие
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Стрелки или <kbd value="W">
        
      </kbd>
      
       <kbd value="A">
        
      </kbd>
      
       <kbd value="S">
        
      </kbd>
      
       <kbd value="D">
        
      </kbd>
    </td>
    
    <td>
      Толкнуть рукоятку в ту сторону, наполовину; с <kbd value="Shift">
        
      </kbd>
      
       — до упора
    </td>
  </tr>
  
  <tr>
    <td>
      <kbd value="G">
        
      </kbd>
    </td>
    
    <td>
      Взять выбранный элемент
    </td>
  </tr>
  
  <tr>
    <td>
      <kbd value="Space">
        
      </kbd>
      
       / <kbd value="Enter">
        
      </kbd>
    </td>
    
    <td>
      Бросить
    </td>
  </tr>
  
  <tr>
    <td>
      <kbd value="Escape">
        
      </kbd>
    </td>
    
    <td>
      Отменить
    </td>
  </tr>
  
  <tr>
    <td>
      <kbd value="P">
        
      </kbd>
    </td>
    
    <td>
      Выбрать на странице
    </td>
  </tr>
</tbody>
</table>

## Options

Каждую опцию, которая не является колбэком, можно править, пока приложение работает. Выберите
узел и откройте **Options**:

<table>
<thead>
  <tr>
    <th>
      Узел
    </th>
    
    <th>
      Опции
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      Провайдер
    </td>
    
    <td>
      <code>
        overlayFit
      </code>
      
      , <code>
        autoScroll
      </code>
      
      , <code>
        collision
      </code>
      
      , <code>
        modifiers
      </code>
      
       (библиотечные, по имени), <code>
        animation
      </code>
      
      , <code>
        dropAnimation
      </code>
      
      , <code>
        animateChanges
      </code>
      
      , <code>
        activation
      </code>
      
      , <code>
        keyboard
      </code>
      
      , <code>
        haptics
      </code>
      
      , <code>
        copyModifier
      </code>
      
      …
    </td>
  </tr>
  
  <tr>
    <td>
      Список
    </td>
    
    <td>
      <code>
        disabled
      </code>
      
      , <code>
        strategy
      </code>
      
      , <code>
        placeholder
      </code>
      
      , <code>
        behavior
      </code>
      
      , <code>
        multiple
      </code>
      
      , <code>
        sort
      </code>
      
      , <code>
        dropOutside
      </code>
      
      , <code>
        acceptMode
      </code>
      
      , <code>
        animation
      </code>
      
      , <code>
        animateChanges
      </code>
      
      , <code>
        autoScroll
      </code>
      
      , <code>
        modifiers
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Дерево
    </td>
    
    <td>
      <code>
        placeholder
      </code>
      
      , <code>
        indentation
      </code>
      
      , <code>
        nesting
      </code>
      
      , <code>
        maxDepth
      </code>
      
      …
    </td>
  </tr>
  
  <tr>
    <td>
      Цель
    </td>
    
    <td>
      <code>
        disabled
      </code>
      
      , <code>
        priority
      </code>
      
      , <code>
        accept
      </code>
      
      , <code>
        acceptMode
      </code>
    </td>
  </tr>
  
  <tr>
    <td>
      Элемент
    </td>
    
    <td>
      <code>
        disabled
      </code>
      
      , <code>
        keyboardMode
      </code>
      
      , <code>
        activation
      </code>
    </td>
  </tr>
</tbody>
</table>

Правка применяется сразу, только к этой странице, и никогда не записывается в ваш код: библиотека
читает новое значение там, где читает опцию. Она действует, пока вы её не сбросите (↺ у каждой
опции или сброс на верхней панели), пока провайдер не размонтируется или страница не
перезагрузится. Рядом с изменённой опцией показано значение из вашего кода. Элементы,
смонтированные, пока правка задана, — строки виртуального списка — тоже её получают.

## State

Что знает каждый провайдер о выбранном узле:

- **сессия драга**: статус, активные id, элементы и сенсор, цель и принимает ли она, указатель,
оверлей, сессия сортируемой группы и линия вставки;
- **список**: его порядок и черновик; **дерево**: его строки;
- **элемент**: его тип, данные и позиция; **цель**: её правила.

Элементы монтируются и размонтируются без событий: реестр догоняет их в течение секунды.

## Log

Одна полоса на драг, по порядку:

<table>
<thead>
  <tr>
    <th>
      Запись
    </th>
    
    <th>
      Что сообщает
    </th>
  </tr>
</thead>

<tbody>
  <tr>
    <td>
      <code>
        drag start
      </code>
    </td>
    
    <td>
      Id, сенсор и было ли это касание, список, из которого пришёл элемент.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        over
      </code>
      
      , <code>
        left
      </code>
    </td>
    
    <td>
      Каждую цель, в которую вошёл и из которой вышел драг, и принимает ли она его.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        release
      </code>
    </td>
    
    <td>
      Цель, над которой драг отпущен, пока решает <code>
        onBeforeDrop
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        onBeforeDrop
      </code>
    </td>
    
    <td>
      Вердикт: принято, принято частично, отклонено хуком, отклонено <code>
        accept
      </code>
      
       цели, и сколько заняли хуки.
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        drop
      </code>
    </td>
    
    <td>
      Цель; для сортируемых списков — перемещение, <code>
        e.result
      </code>
      
       и был ли вызван <code>
        preventDefault()
      </code>
      
      .
    </td>
  </tr>
  
  <tr>
    <td>
      <code>
        cancel
      </code>
    </td>
    
    <td>
      Причина: отменено (Escape, <code>
        cancel()
      </code>
      
      ), отклонено хуком или отклонено <code>
        accept
      </code>
      
       цели.
    </td>
  </tr>
</tbody>
</table>

А также `auto-scroll on` и `off`, тексты `announcement` (по умолчанию скрыты) и, вне драгов,
`animate` (изменения элементов списка, сделанные не драгом). Кликните по записи, чтобы увидеть её
данные. Вкладка, открытая позже, получает уже прошедшие драги.

## Отладка броска по шагам

Карточка не попадает в колонку. С открытой вкладкой:

1. **Воспроизведите** это руками или через **Drive**, чтобы руки оставались свободными для
вкладки.
2. **Следите за картой**, пока карточка над колонкой. Красный значит, что список отклоняет
карточку: смотрите его `group` (`put`) или `accept` цели. Синий значит, что он принимает, и
проблема возникает позже.
3. **Прочитайте журнал** этого драга. `onBeforeDrop` говорит, кто сказал «нет», — хук или
`accept` цели. Если бросок прошёл, а ваши данные не изменились, запись `drop` говорит, был ли
вызван `preventDefault()` и что было в `e.result`: управляемый список должен применять его сам.
4. **Попробуйте исправление вживую** в **Options** — более мягкий `acceptMode`, другой
`collision`, `placeholder: 'indicator'`, — а затем перенесите то, что сработало, в свой код.

## Как это работает

Провайдеры сообщают о себе хуку, который устанавливает сторона страницы. Пока за страницей не
следит вкладка, они только записываются; затем страница слушает, как любой монитор, и отправляет
вкладке то, что та показывает, — каждые 40 ms во время драга, дважды в секунду в остальное время,
— и останавливается, когда несколько секунд за ней не следит ни одна вкладка. Вкладка общается со
страницей через `BroadcastChannel` origin страницы. Она не меняет ничего, кроме того, о чём вы
просите: драгов, выделения и переопределений опций.

## Sitemap

See the full [sitemap](https://zizigy.github.io/vue-dnd-kit/sitemap.md) for all pages.
