ReactJS无外部库看板拖拽:无法获取目标阶段问题求助
React看板拖拽问题:无法获取阶段信息的解决方法
问题根源
- 你的
<h2>阶段标题标签没有设置name或value属性,所以打印这两个值必然是undefined。 - 拖拽事件的
e.target可能指向h2内部的文本节点(而非h2元素本身),导致无法正确获取阶段标识。
解决方案
1. 给阶段标题绑定阶段标识
在<h2>上添加data-stage属性存储阶段名称,同时使用e.currentTarget(而非e.target)获取绑定事件的元素,避免target指向子节点的问题。
2. 完善拖拽事件逻辑
- 拖拽开始时,用
dataTransfer存储被拖拽任务的关键信息(任务名、原阶段)。 - 拖拽经过时,必须调用
e.preventDefault(),否则drop事件不会触发。 - 拖拽完成时,获取传递的数据,更新状态将任务移动到目标阶段。
修改后的完整代码
import { useState } from "react"; export function DragAndDropDemo() { const [stages, setStages] = useState([ { name: "todo", bgcolor: "green", tasks: [ {name: "Integrate Slack"} ] }, { name: "wip", bgcolor: "yellow", tasks: [ {name: "Learn Angular"}, {name: "React"} ] }, { name: "complete", bgcolor: "orange", tasks: [ {name: "Vue"} ] } ]); const handleOnDragStart = (e, taskName, sourceStage) => { // 存储拖拽的任务信息 e.dataTransfer.setData("taskName", taskName); e.dataTransfer.setData("sourceStage", sourceStage); }; const handleOnDragOver = (e) => { e.preventDefault(); // 必须调用,否则drop事件不触发 const targetStage = e.currentTarget.dataset.stage; console.log("拖拽经过阶段:", targetStage); }; const handleOnDrop = (e) => { e.preventDefault(); const taskName = e.dataTransfer.getData("taskName"); const sourceStage = e.dataTransfer.getData("sourceStage"); const targetStage = e.currentTarget.dataset.stage; if (sourceStage === targetStage) return; // 同一阶段不处理 // 复制原状态,避免直接修改 const newStages = [...stages]; // 从原阶段移除任务 const sourceIndex = newStages.findIndex(s => s.name === sourceStage); newStages[sourceIndex].tasks = newStages[sourceIndex].tasks.filter(t => t.name !== taskName); // 添加到目标阶段 const targetIndex = newStages.findIndex(s => s.name === targetStage); newStages[targetIndex].tasks.push({name: taskName}); setStages(newStages); console.log(`任务${taskName}从${sourceStage}移动到${targetStage}`); }; return ( <div> {stages.map((stage_item) => { return ( <div key={stage_item.name} style={{backgroundColor: stage_item.bgcolor, float: "left", border: "#000 1px solid", margin: "0 10px"}}> <h2 data-stage={stage_item.name} className="droppable" onDragOver={handleOnDragOver} onDrop={handleOnDrop} style={{border: "#000 1px dashed", padding: "10px", margin: "1px"}} > {stage_item.name} </h2> {stage_item.tasks.map((task_item) => { return( <div key={`${stage_item.name}-${task_item.name}`} onDragStart={(e) => handleOnDragStart(e, task_item.name, stage_item.name)} draggable className="draggable" style={{backgroundColor: "white", border: "#ccc 1px solid", padding: "10px", margin: "5px"}} > <p>{task_item.name}</p> </div> ); })} </div> ) })} <div style={{clear: "both"}}></div> </div> ); } export default DragAndDropDemo;
额外优化点
- 用
stage_item.name作为key(而非索引),避免阶段顺序变化导致的渲染问题。 - 任务的key使用
${stage_item.name}-${task_item.name},确保同一任务在不同阶段的key唯一。
内容的提问来源于stack exchange,提问作者Europa
相关产品推荐
相关产品推荐

