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

如何让基于dnd-kit的可拖拽Div同时支持编辑功能?

解决@dnd-kit/core中可拖拽组件内编辑按钮无法点击的问题

你的问题出在两个核心点:语法错误和拖拽事件与按钮点击的冲突,下面是具体修复方案:

问题1:无效语法导致状态更新失败

你在handleBlur函数里写了错误的语法:

const handleBlur = () `your text`=> {
  setIsEditing(false);
};

多余的your text会导致函数无法正常执行,直接修正为标准箭头函数写法即可。

问题2:拖拽事件拦截了按钮点击

useSortable返回的listeners包含pointerdown监听,当你把{...listeners}绑定到整个容器div上时,这个监听会拦截所有子元素的点击事件,包括编辑按钮的点击。

解决方法是将拖拽交互限制在单独的手柄元素上,不让整个容器响应拖拽,这样按钮的点击事件就能正常触发。

修复后的完整代码

import React, { useState, useEffect } from 'react';
import { closestCenter, DndContext, PointerSensor, useSensor } from '@dnd-kit/core';
import { arrayMove, SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';

const UserComponent = ({
  id,
  body
}) => {
  const [isEditing, setIsEditing] = useState(false);

  const toggleEditing = () => {
    setIsEditing(!isEditing);
  };

  // 修正语法错误
  const handleBlur = () => {
    setIsEditing(false);
  };

  const {
      setNodeRef,
      attributes,
      listeners,
      transition,
      transform,
      isDragging,
  } = useSortable({ id: id })

  const style = {
      transition,
      transform: CSS.Transform.toString(transform),
      border: '2px solid black',
      marginBottom: 5,
      marginTop: 5,
      display: "flex",
      alignItems: "center",
      gap: "10px",
      padding: "8px",
      opacity: isDragging ? 0.5 : 1,
  }

  return (
      <div
          ref={setNodeRef}
          style={style}
      >
        {/* 仅给拖拽手柄绑定拖拽相关属性与监听 */}
        <div {...attributes} {...listeners} style={{cursor: "grab"}}>☰</div>
        <button onClick={toggleEditing}>Edit</button>
        <div
          contentEditable={isEditing}
          onBlur={handleBlur}
          suppressContentEditableWarning
          style={{flex: 1, textAlign: "left"}}
        >
          {body}
        </div>
      </div>
  )
}

function DragApp() {

  const [items, setItems] = useState([
      {
        id: "1",
        name: "Manoj",
        body: "Sample text 1"
      },
      {
        id: "2",
        name: "John",
        body: "Sample text 2"
      },
      {
        id: "3",
        name: "Ronaldo",
        body: "Sample text 3"
      },
      {
        id: "4",
        name: "Harry",
        body: "Sample text 4"
      },
      {
        id: "5",
        name: "Jamie",
        body: "Sample text 5"
      }
    ])

  useEffect(() => {
      fetch('https://jsonplaceholder.typicode.com/posts')
        .then((response) => response.json())
        .then((data) => setItems(data));
    }, []);

const sensors = [useSensor(PointerSensor)];

const handleDragEnd = ({active, over}) => {
  if (active.id !== over.id) {
    setItems((items) => {
      const oldIndex = items.findIndex(item => item.id === active.id)
      const newIndex = items.findIndex(item => item.id === over.id)

      return arrayMove(items, oldIndex, newIndex)
    })
  }
}

return (
  <div
    style={{
      margin: 'auto',
      width: 1000,
      textAlign: 'center',
    }}
  >
    <DndContext
      sensors={sensors}
      collisionDetection={closestCenter}
      onDragEnd={handleDragEnd}
    >
      <SortableContext
        items={items.map(item => item.id)}
        strategy={verticalListSortingStrategy}
      >
        {
          items.map(
            item => <UserComponent {...item} key={item.id} />
          )
        }
      </SortableContext>
    </DndContext>
  </div>
);
}

export default DragApp;

关键修复说明

  1. 修正handleBlur语法错误,确保失去焦点时能正常关闭编辑状态。
  2. 将拖拽相关的attributes和listeners从容器div移到单独的拖拽手柄上,只有点击手柄才触发拖拽,不会干扰编辑按钮的点击。
  3. 调整容器为flex布局,让拖拽手柄、按钮和文本区域的布局更合理。

内容的提问来源于stack exchange,提问作者Dan Gleason

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 05:50:20