Документация/Руководства

DevTools

Вкладка Vue DnD Kit во Vue DevTools и Nuxt DevTools — живая мини-карта, джойстик, который перетаскивает по-настоящему, правка опций на лету и журнал каждого драга.

Редактировать страницу

Страница переведена ИИ и может содержать неточности. Читать английский оригинал

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

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

Установка

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

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

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

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

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()],
});

С 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-сетапы), установите сторону страницы сами:

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, которое раздаёт вкладку.

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

Как открыть

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

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

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

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

Мини-карта

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

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

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

Drive: джойстик

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

Это настоящий драг указателем от сенсора по имени devtools, сделанный на публичном API сенсоров: списки сортируются под ним, контейнеры прокручиваются у краёв, а onBeforeDrop и onDrop выполняются, как для любого драга. Отключённые элементы не берутся. Перетаскиванием с клавиатуры, начатым на странице, тоже можно управлять.

Элементы сортируемых списков получают ещё и кнопки: вверх, вниз, в начало, в конец, в другой список группы. Каждая — одно перетаскивание с клавиатуры через moveItem. Под джойстиком — крупная копия того, что показывает оверлей.

Клавиша во вкладкеДействие
Стрелки или W A S DТолкнуть рукоятку в ту сторону, наполовину; с Shift — до упора
GВзять выбранный элемент
Space / EnterБросить
EscapeОтменить
PВыбрать на странице

Options

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

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

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

State

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

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

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

Log

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

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

А также 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 страницы. Она не меняет ничего, кроме того, о чём вы просите: драгов, выделения и переопределений опций.