项目背景

在日常开发中,看板(Kanban)任务管理是团队协作的标配工具。市面上虽然有很多成熟产品,但我想尝试用 AI 辅助编程快速搭建一个轻量级、高颜值、可定制的看板组件,既能满足个人项目管理需求,也能作为 Vue 3 拖拽交互的最佳实践案例。

技术选型:

  • Vue 3 Composition API(<script setup>)
  • Tailwind CSS(快速构建现代 UI)
  • HTML5 原生 Drag & Drop API(零依赖实现拖拽)
  • Vite 5(构建工具)

核心目标:

  1. 支持任务卡片跨列拖拽 + 列内排序
  2. 暗黑模式一键切换
  3. 数据本地持久化(localStorage)
  4. 零第三方拖拽库依赖

实现过程

1. 核心功能:拖拽逻辑设计

拖拽是看板的核心交互。我采用了 Vue 3 的 provide/inject 模式,在父组件 KanbanBoard.vue 中统一管理拖拽状态,子组件 TaskCard.vue 通过 @dragover.stop 实现精确插入位置判断。

关键代码片段:

// 拖拽运行时状态

const drag = reactive({

  taskId: null,      // 正在被拖拽的任务 id

  fromColId: null,   // 拖拽来源列 id

  overColId: null,   // 当前悬停目标列 id

  overIndex: null,   // 当前悬停插入位置索引

})

 

// 卡片开始拖拽:写入 dataTransfer(Firefox 必需)

function startDrag(e, taskId, colId) {

  e.dataTransfer.setData('text/plain', taskId)

  e.dataTransfer.effectAllowed = 'move'

  drag.taskId = taskId

  drag.fromColId = colId

}

 

// 悬停在卡片上:按鼠标相对卡片中点的位置,决定插到该卡片前还是后

function dragOverCard(colId, index, e) {

  e.preventDefault()  // 必须 preventDefault 才允许 drop

  drag.overColId = colId

  const rect = e.currentTarget.getBoundingClientRect()

  const midY = rect.top + rect.height / 2

  drag.overIndex = e.clientY < midY ? index : index + 1

}

 

// 核心移动:从源列移除,插入目标列指定位置

function moveTask(fromColId, taskId, toColId, toIndex) {

  const fromCol = columns.value.find(c => c.id === fromColId)

  const toCol = columns.value.find(c => c.id === toColId)

  const i = fromCol.tasks.findIndex(t => t.id === taskId)

  const [task] = fromCol.tasks.splice(i, 1)   // 先移除

 

  // 同列向后移动时,splice 已删一个元素,目标索引要 -1 修正

  let at = toIndex

  if (fromColId === toColId && i < toIndex) at = toIndex - 1

  at = Math.max(0, Math.min(at, toCol.tasks.length))

  toCol.tasks.splice(at, 0, task)

}

设计亮点:

  • 使用 @dragover.stop 阻止事件冒泡,避免列容器的 dragover 覆盖精确索引
  • 通过 getBoundingClientRect() 计算鼠标相对卡片中点位置,实现智能插入(上半区插前,下半区插后)
  • 同列拖拽时的索引修正逻辑(i < toIndex 时 toIndex - 1)

2. UI 设计:Tailwind CSS 快速构建

卡片组件采用 group hover 模式,删除按钮默认隐藏,鼠标悬停时渐现:

<div

  draggable="true"

  @dragstart="kanban.startDrag($event, task.id, colId)"

  @dragend="kanban.endDrag()"

  @dragover.stop="kanban.dragOverCard(colId, index, $event)"

  class="group p-3 rounded-lg bg-white dark:bg-gray-700 shadow-sm

         hover:shadow-md hover:-translate-y-1 transition-all

         cursor-grab active:cursor-grabbing"

  :class="isDragging ? 'opacity-50' : 'opacity-100'"

>

  <div class="flex justify-between items-start">

    <span class="text-sm text-gray-800 dark:text-gray-100">{{ task.title }}</span>

    <button

      @click="kanban.deleteTask(colId, task.id)"

      class="opacity-0 group-hover:opacity-100 transition-opacity text-gray-400 hover:text-red-500"

    >

      ×

    </button>

  </div>

</div>

暗黑模式实现:

  • 使用 localStorage 持久化主题状态
  • Tailwind 的 dark: 前缀自动切换颜色
  • 按钮文案动态切换亮色模式/暗色模式

踩坑全记录(代码5分钟,环境调20分钟)

先说结论: 代码层面一次写对——我用 Vue 官方 @vue/compiler-sfc 校验四个组件,<script setup>、模板编译全部通过,拖拽逻辑、Tailwind 暗黑模式都没返工。真正的坑全在构建工具链,而且是一个套一个,排查了 12 轮才最终跑通。

坑 1:npm run build 静默失败,dist 无产物

现象: 执行 npm run build 后,终端只显示命令回显,没有报错,但 dist/ 目录为空。

排查: npm 提示 install-scripts not yet covered,怀疑 esbuild 的 postinstall 脚本没执行。

尝试:

npm install-scripts approve esbuild

npm rebuild esbuild

坑 2:rebuild esbuild 报 status: 3221226505(Windows 0xC0000409)

现象: npm rebuild esbuild 失败,错误码 3221226505 对应 Windows 的 STATUS_STACK_BUFFER_OVERRUN。

根因确认:

# 直接运行 esbuild 二进制测试

& "node_modules\esbuild\win32-x64\esbuild.exe" --version

# 输出:exit=-1073740791(0xC0000409)

结论: esbuild 的 Windows 二进制文件本身执行就崩溃,与 Node/npm 无关。Node 版本是 v26.7.0(非 LTS 预览版),搭配的 esbuild 0.21.5 二进制不兼容。

坑 3:升级 esbuild@latest 被 postinstall 回滚

尝试:

npm install esbuild@latest -D

问题: 新包的 install.js 脚本验证二进制失败,导致回滚到 0.21.5。

解法:

npm install esbuild@0.25.5 -D --ignore-scripts

# 手动验证

esbuild.exe --version  # 输出 0.25.5, exit=0

坑 4:顶层 esbuild 升了,build 仍报 "The service was stopped"

现象: 升级顶层 esbuild 后,npm run build 仍然失败。

排查: 报错栈指向 node_modules/vite/node_modules/esbuild/lib/main.js

根因: Vite 自带了一个嵌套的旧版 esbuild(0.21),我升的是顶层,Vite 用的还是嵌套版本。这是最隐蔽的一坑。

坑 5:overrides 与直接依赖冲突 EOVERRIDE

尝试: 在 package.json 添加:

{

  "overrides": {

    "esbuild": "0.25.5"

  }

}

问题: npm 报 Override for esbuild conflicts with direct dependency。

解法: 从 devDependencies 删除 esbuild 直接依赖(它本就是 vite 的间接依赖,不该手动列),只保留 overrides。

坑 6:清装时 rollup 的 .node 文件 EPERM

现象: Remove-Item node_modules 清理时,rollup 的原生 .node 文件因 OneDrive 同步占用无法删除。

影响: 只是清理警告,安装仍成功。

坑 7:npm run dev 端口 5173 被占

现象: Vite 自动切换到 5174。

解决: 非问题,但预览 URL 要对应修改。

坑 8:验证嵌套 esbuild 已被替换

验证脚本:

node -e "const fs=require('fs');

const p='node_modules/vite/node_modules/esbuild/package.json';

console.log('vite 嵌套 esbuild:', fs.existsSync(p) ? require(p).version : '已提升(无嵌套)');

console.log('顶层 esbuild:', require('esbuild/package.json').version)"

输出:

vite 嵌套 esbuild: 已提升(无嵌套)

顶层 esbuild: 0.25.5

结论: 嵌套旧版已消除,全局统一为 0.25.5。

坑 9:最终构建验证

npm run build 2>&1 | Out-String

结果:

  • 构建成功
  • 产物已生成(dist/ 下 html + css 13KB + js 72KB)
  • 3.05s 完成
  • 问题已彻底修复

好用的 Prompt 分享

为了让码道生成高质量代码,我使用了以下结构化 Prompt:

# 角色设定

你是一位拥有10年经验的资深前端架构师,精通 Vue 3 和现代 CSS 框架,擅长编写高可维护、高颜值的组件。

 

# 任务目标

请使用 Vue 3 (Composition API, <script setup>) 和 Tailwind CSS 编写一个看板(Kanban)任务管理组件。要求代码结构清晰,UI 现代且美观。

 

# 功能需求

1. 看板包含三个默认列:待办 (To Do)、进行中 (In Progress)、已完成 (Done)。

2. 支持在每列中添加、删除任务卡片。

3. 支持任务卡片在列与列之间、以及列内部进行拖拽排序(请使用原生 HTML5 Drag and Drop API 实现)。

4. 数据持久化:使用 localStorage 保存看板数据,刷新页面不丢失。

5. 暗黑模式:提供一个切换按钮,支持亮色/暗色主题切换。

 

# UI/UX 设计要求

1. 整体布局:全屏高度,三列等宽,列之间留有适当间距。

2. 卡片设计:带有轻微的阴影(shadow-sm),圆角(rounded-lg),hover 时有上浮效果(hover:-translate-y-1 transition-transform)。

3. 颜色搭配:

   - 亮色模式:背景为浅灰(bg-gray-100),卡片为纯白。

   - 暗色模式:背景为深灰(bg-gray-900),卡片为稍浅的深灰(bg-gray-800)。

4. 交互反馈:拖拽时,被拖拽的卡片透明度降低(opacity-50),放置目标列有高亮提示。

 

# 代码规范要求

1. 请将代码整合在一个 Vue 单文件组件 (SFC) 中。

2. 使用 Tailwind CSS 进行样式编写,不要使用自定义 CSS。

3. 关键逻辑(如拖拽处理、本地存储同步)必须添加详细的中文注释。

Prompt 设计技巧:

  1. 明确角色: 让 AI 以"资深架构师"身份思考,代码质量更高
  2. 分点列举: 功能需求、UI 设计、代码规范分开写,避免遗漏
  3. 技术约束: 明确"不要自定义 CSS"、"使用原生 API"等边界
  4. 注释要求: 强制要求中文注释,便于后续维护

效果展示

截图 1:初始空状态(亮色模式)

  • 顶部工具栏:标题看板任务管理 + 亮色模式按钮
  • 三列等宽并排,列头带蓝/黄/绿色点
  • 空列显示"暂无任务"灰色提示

截图 2:添加任务交互

  • 列头"+"按钮点击后,下方展开输入框 + 添加按钮
  • 支持回车快速添加

截图 3:三列各有任务卡片

  • 卡片白底、圆角、阴影
  • hover 时上浮效果 + 右侧"×"删除按钮渐现
  • 列头任务计数实时更新

截图 4:拖拽中状态(最关键)

  • 被拖卡片半透明(opacity-50)
  • 目标列蓝色 ring-2 边框高亮
  • 鼠标悬停处蓝色细横线指示插入位置
  • 鼠标变 grab/grabbing 手型

截图 5:暗黑模式

  • 整页背景深灰(bg-gray-900)
  • 列容器 bg-gray-800,卡片 bg-gray-700
  • 按钮文案变为"暗色模式"

截图 6:跨列拖拽完成

  • 卡片成功移动到目标列
  • 列计数自动更新

总结与技巧提炼

1. 技术层面的收获

拖拽交互最佳实践:

  • 使用 HTML5 原生 Drag & Drop API,零依赖
  • e.dataTransfer.setData() 在 Firefox 中必需,否则不触发拖拽
  • @dragover.stop 阻止冒泡是实现精确插入位置的关键
  • 同列拖拽时的索引修正逻辑(i < toIndex 时 toIndex - 1)

Vue 3 Composition API 优势:

  • provide/inject 模式让父子组件通信更清晰
  • reactive 统一管理拖拽状态,避免 prop drilling

Tailwind CSS 开发效率:

  • group + group-hover 实现卡片删除按钮渐现
  • dark: 前缀一键切换暗黑模式
  • hover:-translate-y-1 等工具类快速实现微交互

2. 环境踩坑的经验

核心教训:

  1. Node 版本选择: 别用非 LTS 预览版跑构建链(v26.7.0 + esbuild 0.21 二进制不兼容)
  2. overrides 是利器: 统一嵌套重复依赖(Vite 自带的 esbuild)
  3. --ignore-scripts 慎用: 升级 esbuild 时需跳过 postinstall,但装完后要手动验证二进制
  4. 嵌套依赖陷阱: 顶层升了 esbuild,Vite 用的还是嵌套版本,必须用 overrides 强制统一

排查思路:

  • 从报错栈定位具体文件(vite/node_modules/esbuild/lib/main.js)
  • 直接运行二进制文件验证(esbuild.exe --version)
  • 检查 node -p "process.arch" 确认架构匹配

3. 最终修复清单(三步走)

步骤 1: 修改 package.json

{

  "devDependencies": {

    "@vitejs/plugin-vue": "^5.0.4",

    "vite": "^5.2.0"

  },

  "overrides": {

    "esbuild": "0.25.5"

  }

}

步骤 2: 彻底清理

Remove-Item -Recurse -Force node_modules, package-lock.json

步骤 3: 干净重装

npm install --ignore-scripts

npm run build

4. AI 辅助编程的心得

代码生成:

  • 结构化 Prompt 比自然语言更有效
  • 明确技术约束("不要自定义 CSS")避免 AI 自由发挥
  • 要求中文注释,便于后续维护

代码验证:

  • 使用 Vue 官方编译器 @vue/compiler-sfc 校验语法
  • 拖拽逻辑、Tailwind 类名一次写对,节省大量调试时间

时间分配:

  • 代码生成:5 分钟
  • 环境调试:20 分钟
  • 效果验证:5 分钟

结论: AI 能帮你快速写出正确的代码,但环境配置、依赖冲突等"脏活累活"还得自己扛。不过,踩坑的过程本身就是宝贵的经验积累!

5. 额外提示

关于 rollup 的 .node 文件 EPERM 警告:

  • 这是 OneDrive 同步占用导致的清理警告,不影响运行
  • 如果介意,可以把项目移出 OneDrive 目录

关于 Node 版本建议:

  • Node v26 是非 LTS 预览版,存在兼容性问题
  • 长期建议:换用 Node 20/22 LTS 版本更稳妥
  • 生产环境务必使用 LTS 版本

项目源码

完整项目包含 11 个文件,核心组件:

  • KanbanBoard.vue(拖拽逻辑 + 状态管理)
  • TaskCard.vue(卡片组件 + DnD 绑定)
  • Column.vue(列容器 + 添加任务)
  • package.json(overrides 配置是关键)

最后说一句: 如果你也在用码道做项目,遇到构建问题别慌,先查嵌套依赖,再用 overrides 强制统一版本,大概率能解决!

相关文件下载
码道案例_Vue3拖拽看板实战.docx
18.96 KB
下载
kanban-vue.rar
16.58 MB
下载
Logo

华为AI开发者空间,是为全球开发者打造的专属开发空间,汇聚了华为优质开发资源及工具,致力于让每一位开发者拥有一台云主机,基于华为根生态开发、创新。

更多推荐