无需第三方库实现Vue多列跨列及列内可排序拖拽的方案咨询
原生实现JIRA风格可拖拽看板的实现方案(Vue优先)
基础逻辑框架
完全基于HTML5原生Drag & Drop API实现,无任何第三方依赖,核心拆为状态管理、拖拽事件响应、位置计算更新三个模块即可。
Vue 3 实现步骤
- 定义数据结构
采用「列-任务」两层嵌套响应式结构,示例定义:import { ref } from 'vue' // 看板列配置 const boardColumns = ref([ { id: 'todo', name: '待处理', tasks: [ { id: 'task_001', content: '完成首页接口联调', priority: 1 }, { id: 'task_002', content: '修复用户登录异常问题', priority: 2 } ]}, { id: 'in_progress', name: '进行中', tasks: [] }, { id: 'done', name: '已完成', tasks: [] } ]) // 拖拽临时状态 const draggingTask = ref(null) const fromColumnId = ref('') const hoverTarget = ref({ columnId: '', taskId: null, position: 'before' }) // position可选before/after - 绑定拖拽核心事件
给任务卡片设置draggable="true"属性,绑定对应事件:dragstart事件:触发时记录当前拖拽任务对象、起始列ID,给拖拽元素添加半透明样式做状态反馈dragend事件:触发时清空所有拖拽临时状态,还原元素样式
给所有任务卡片、列的任务容器绑定dragover事件,阻止默认行为,同时计算悬停位置:
const handleDragOver = (e, targetColumnId, targetTaskId = null) => { e.preventDefault() // 计算当前拖拽点相对于目标任务的位置,判断插入到上方还是下方 if (targetTaskId) { const targetRect = e.currentTarget.getBoundingClientRect() const midY = targetRect.top + targetRect.height / 2 hoverTarget.value = { columnId: targetColumnId, taskId: targetTaskId, position: e.clientY < midY ? 'before' : 'after' } } else { // 悬停在空列容器中,直接插入到列末尾 hoverTarget.value = { columnId: targetColumnId, taskId: null, position: 'after' } } } - 实现drop事件的更新逻辑
给任务卡片、列的任务容器绑定drop事件,触发时根据拖拽状态更新数据:const handleDrop = (e) => { e.preventDefault() // 从原列删除拖拽任务 const fromColumn = boardColumns.value.find(col => col.id === fromColumnId.value) const taskIndex = fromColumn.tasks.findIndex(t => t.id === draggingTask.value.id) fromColumn.tasks.splice(taskIndex, 1) // 插入到目标位置 const targetColumn = boardColumns.value.find(col => col.id === hoverTarget.value.columnId) if (hoverTarget.value.taskId === null) { // 空列直接插入末尾 targetColumn.tasks.push(draggingTask.value) } else { const targetIndex = targetColumn.tasks.findIndex(t => t.id === hoverTarget.value.taskId) const insertIndex = hoverTarget.value.position === 'before' ? targetIndex : targetIndex + 1 targetColumn.tasks.splice(insertIndex, 0, draggingTask.value) } } - 交互优化
- 拖拽过程中给被拖拽元素添加
opacity: 0.5、cursor: grab的样式 - 根据
hoverTarget的位置在对应点位显示插入提示线,明确释放后的插入位置 - 可扩展添加拖动时列容器自动滚动、拖拽范围限制等自定义逻辑
- 拖拽过程中给被拖拽元素添加
其他技术栈通用实现思路
核心逻辑完全通用,仅需将状态管理部分替换为对应框架的响应式实现即可,原生JS实现可直接操作DOM节点的增删完成位置更新。
内容的提问来源于stack exchange,提问作者Nata Vacheishvili
相关产品推荐
相关产品推荐

