You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ReactJS无外部库看板拖拽:无法获取目标阶段问题求助

React看板拖拽问题:无法获取阶段信息的解决方法

问题根源

  1. 你的<h2>阶段标题标签没有设置name或value属性,所以打印这两个值必然是undefined。
  2. 拖拽事件的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.07 14:01:42