文档/指南

DevTools

Vue DevTools 和 Nuxt DevTools 中的 Vue DnD Kit 标签页——实时小地图、能真正拖拽的摇杆、实时编辑选项,以及每次拖拽的日志。

编辑此页

本页由 AI 翻译,可能存在不准确之处。 阅读英文原文

@vue-dnd-kit/devtools 在 Vue DevTools(vite-plugin-vue-devtools)和 Nuxt DevTools 中添加一个 Vue DnD Kit 标签页。它在实时小地图中显示页面上的每个列表、树和放置目标,用摇杆拖拽任意项,在应用运行时编辑选项,并记录每次拖拽做了什么。它只在开发环境中工作:它的任何部分都不会进入生产构建。

这个标签页是一个独立的页面,由你的开发服务器在你的应用旁边提供,所以无法在本文档中运行。三步即可完成设置。

安装

1. 添加包

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

@vue-dnd-kit/actions 是一个对等依赖:标签页中的移动都通过它进行。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 时,插件在开发服务器(vite serve)上做三件事:在 /__vue-dnd-kit-devtools/(位于你的 base 之下)提供标签页,把它添加到 Vue DevTools 中,并让页面在你的应用启动之前向它报告。不需要 app.use(),构建也不受影响。

使用 Nuxt 时,@vue-dnd-kit/nuxt 模块会找到这个包,提供标签页,把它添加到 Nuxt DevTools 中,并通过一个客户端插件安装页面一侧的部分。vueDndKit: { devtools: false } 关闭它。

3. 在开发环境中运行应用

像往常一样启动开发服务器(vite、nuxt dev)并打开应用:标签页就绪。页面上的每个 provider 都会显示在其中,无论它在哪个应用中渲染。

不使用插件

对于你自己的开发服务器,或者不是由 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 });@vue-dnd-kit/devtools/vite 中的 serveTab() 就是提供标签页的中间件。

在生产构建中,app.use(DnDDevtools) 和 auto 导入几乎缩减为零:每个入口点都会先检查 process.env.NODE_ENV,打包工具会去掉其余部分。在服务端它们什么都不做。

打开它

  • Vue DevTools::kbd{value="Alt"} + Shift + D,或页面底部的 Vue 按钮,然后选择 Vue DnD Kit 标签页。
  • Nuxt DevTools::kbd{value="Alt"} + Shift + D,或 Nuxt 按钮,然后选择 Vue DnD Kit(在侧边栏或它的溢出菜单中)。
  • 独立窗口:在你的开发服务器上打开 http://localhost:5173/__vue-dnd-kit-devtools/,或点击标签页的 ⧉ 按钮。在第二块屏幕上很方便。打开了多个页面时,顶部的下拉框可以选择要观察的那个。
把标签页放在单独的窗口中,而不是同一窗口中的后台浏览器标签页:页面必须保持可见,隐藏的页面会取消拖拽。

标签页一览

部分内容
顶栏拖拽此刻正在做什么(dragging card-3 → done (accepts))、被观察的页面、⌖ Pick、已编辑选项的数量及重置按钮、⧉(独立窗口)以及主题。
左侧:注册表以树的形式显示每个 provider:它的列表、树、放置目标和可拖拽元素。☰ 显示或隐藏它。
中间:Map 和 Log页面的实时小地图,或拖拽日志。
右侧:Drive、Options、State摇杆和移动按钮、所选节点的选项,以及 provider 对它所知的信息。

在注册表中选择一个节点,或在地图上选择一个项,右侧就会跟随它。

小地图

每个列表、树和放置目标都有一张实时卡片,其中的项的副本位于它们所在的位置——与浮层会显示的克隆相同,并带有页面的 CSS。拖拽期间它会标出:

  • 接收该拖拽(蓝色)或拒绝该拖拽(红色)的列表和目标;
  • 占位元素,以及指针下方的目标;
  • 指针、浮层的盒子,以及 placeholder: 'indicator' 列表的插入线。

单击会选中一个项并在页面上高亮它;双击会把页面滚动到它那里。当放置没有到达你预期的地方时,使用地图:它一眼就能看出哪些列表接收这次拖拽。

Drive:摇杆

选择一个项——在地图上、在注册表中,或用 ⌖ Pick,它会接管页面上对可拖拽元素的下一次按下,而不让按下产生作用——然后推动摇杆的旋钮。项被拿起并朝那个方向移动,旋钮离中心越远,移动越快。松开它就停下;Drop 和 Cancel 结束拖拽。

这是一个名为 devtools 的传感器发起的真正的指针拖拽,基于公开的传感器 API 实现:列表在它下方排序,容器在边缘自动滚动,onBeforeDrop 和 onDrop 像任何拖拽一样运行。禁用的项不会被拿起。页面发起的键盘拖拽也可以操控。

可排序列表的项还有按钮:上移、下移、移到开头、移到末尾、移到同一分组的另一个列表。每个按钮都是一次 moveItem 键盘拖拽。摇杆下方是浮层所显示内容的一个放大副本。

按键(在标签页中)作用
方向键或 W A S D把旋钮朝那个方向推到一半;按住 Shift 时推到底
G拿起所选的项
Space / Enter放下
Escape取消
P在页面上选取

选项

所有不是回调的选项都可以在应用运行时编辑。选择节点并打开 Options:

节点选项
ProvideroverlayFit、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

编辑立即生效,只作用于当前页面,永远不会写入你的代码:库在读取选项的地方读取新值。它会一直有效,直到你重置它(每个选项旁的 ↺,或顶栏中的重置)、provider 卸载或页面重新加载。被编辑的选项旁边会显示你代码中的值。在编辑生效期间挂载的项——虚拟列表的行——也会获得它。

状态

每个 provider 对你所选节点所知的信息:

  • 拖拽会话:状态、当前的 id、项和传感器、目标及其是否接收、指针、浮层、可排序分组的会话和插入线;
  • 列表:它的顺序和草稿;树:它的行;
  • 项:它的类型、数据和位置;放置目标:它的规则。

项的挂载和卸载没有事件:注册表会在一秒内跟上。

日志

每次拖拽一个条带,按顺序排列:

条目说明什么
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'——然后把有效的那个写进你的代码。

工作原理

provider 向页面一侧安装的一个钩子报告。在有标签页观察该页面之前,它们只是被记录下来;之后页面像任何监听器一样进行监听,并把标签页要显示的内容发送给它——拖拽期间每 40 ms 一次,其他时候每秒两次——在几秒钟内没有标签页观察时停止。标签页通过页面源的 BroadcastChannel 与页面通信。它只改变你要求的东西:拖拽、选中集合和选项覆盖。