antd5实体dnd-kit/sortable 实现简单table拖拽排序

本文介绍了如何在React中使用dnd-kit库创建一个可拖动的表格,包括设置传感器、排序策略和处理拖动事件,展示了如何实现在表格项之间的拖放操作并保持数据同步。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

DratTable/index.tsx


import type { DragEndEvent } from '@dnd-kit/core';
import { DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import { restrictToVerticalAxis } from '@dnd-kit/modifiers';
import {
  SortableContext,
  arrayMove,
  verticalListSortingStrategy
} from '@dnd-kit/sortable';
import { Space, Table } from 'antd';
import { useState } from 'react';
import Row from './components/TableRow';

const DragTable = (props) => {
  const { searchParams } = props;
  const [data, setData] = useState<{
    id: number;
    label: string;
  }[]>([
    {
      id: 1,
      label: 'weee1',
      children: [
        {
          id: 11,
          label: 'ssw1-1'
        },
        {
          id: 12,
          label: 'ssw1-2'
        }
      ]
    },
    {
      id: 2,
      label: 'weee2'
    },
    {
      id: 3,
      label: 'weee3'
    },
    {
      id: 4,
      label: 'weee4'
    }
  ]);

  const columns: any[] = [

    {
      title:'Label',
      dataIndex: 'label',
      ellipsis: true,
     
    },
    {
      title: 'Name',
      dataIndex: 'enLabel',
      ellipsis: true,
    },
    {
      title: 'Key',
      dataIndex: 'nodeId',
      ellipsis: true,
    },

  ];
  const sensors = useSensors(
    useSensor(PointerSensor, {
      activationConstraint: {
        // https://docs.dndkit.com/api-documentation/sensors/pointer#activation-constraints
        distance: 1,
      },
    }),
  );

  const onDragEnd = ({ active, over }: DragEndEvent) => {
    console.log('active, over', active, over);

    if (active.id !== over?.id) {
      setData((prev) => {
        console.log('prev', prev);
        const activeIndex = prev.findIndex((i) => i.id === active.id);
        const overIndex = prev.findIndex((i) => i.id === over?.id);
        return arrayMove(prev, activeIndex, overIndex);
      });
    }
  };

  return (
    <DndContext sensors={sensors} modifiers={[restrictToVerticalAxis]} onDragEnd={onDragEnd}>
      <SortableContext
        items={data.map((i) => i.id)}
        strategy={verticalListSortingStrategy}
      >
        <Table
          rowKey="id"
          components={{
            body: {
              row: Row,
            },
          }}
          columns={columns}
          dataSource={data}
        />
      </SortableContext>
    </DndContext>
  );
};

export default DragTable;

DratTable/components/TableRow/index.tsx

import {
  useSortable
} from '@dnd-kit/sortable';
interface RowProps extends React.HTMLAttributes<HTMLTableRowElement> {
  'data-row-key': string;
}
const Row = (props: RowProps) => {
  const {
    attributes,
    listeners,
    setNodeRef,
    transform,
    transition,
    isDragging
  } = useSortable({
    id: props['data-row-key'],
  });

  const style: React.CSSProperties = {
    ...props.style,
    transform: CSS?.Transform?.toString(transform && { ...transform, scaleY: 1 }),
    transition,
    cursor: 'move',
    ...(isDragging ? { position: 'relative', zIndex: 9999 } : {}),
  };

  return <tr {...props} ref={setNodeRef} style={style} {...attributes} {...listeners} />;
};

export default Row;

在这里插入图片描述

在这里插入图片描述

DndContent组件Props

interface Props {
  announcements?: Announcements;
  autoScroll?: boolean;
  cancelDrop?: CancelDrop;
  children?: React.ReactNode;
  collisionDetection?: CollisionDetection;
  layoutMeasuring?: Partial<LayoutMeasuring>;
  modifiers?: Modifiers;
  screenReaderInstructions?: ScreenReaderInstructions;
  sensors?: SensorDescriptor<any>[];
  onDragStart?(event: DragStartEvent): void;
  onDragMove?(event: DragMoveEvent): void;
  onDragOver?(event: DragOverEvent): void;
  onDragEnd?(event: DragEndEvent): void;
  onDragCancel?(): void;
}

拖拽组件 dnd-kit

官方文档:https://docs.dndkit.com/
GitHub地址:https://github.com/clauderic/dnd-kit

@dnd-kit – 用于 React 的轻量级、模块化、高性能、可访问且可扩展的拖放工具包。

功能丰富:可定制的碰撞检测算法、多个激活器、可拖动覆盖、拖动手柄、自动滚动、约束等等。
专为 React 构建:公开诸如和 之类的钩子,并且不需要您重新构建应用程序或创建额外的包装器 DOM 节点。

支持广泛的用例:列表、网格、多个容器、嵌套上下文、可变大小的项目、虚拟化列表、2D 游戏等。
零依赖和模块化:库的核心缩小后重量约为 10kb,并且没有外部依赖。它是围绕内置的 React 状态管理和上下文构建的,这使库保持了精简。
内置支持多种输入法:指针、鼠标、触摸和键盘传感器。
完全可定制和可扩展:定制每个细节——动画、过渡、行为、样式。构建您自己的、、自定义按键绑定等等。
辅助功能:键盘支持、合理的默认咏叹调属性、可自定义的屏幕阅读器说明和内置的实时区域。
性能:它在构建时考虑了性能,以支持丝般流畅的动画。
预设:需要构建可排序的界面?检查一下,这是一个建立在上面的薄层。未来会有更多预设。@dnd-kit/core

<think>好的,我现在需要解决用户关于如何实现可编辑表格的问题。用户提到了两种已有的引用,分别是关于React Ant Design和Element UI的实现方法。我需要结合这些信息,给出清晰的步骤和示例代码。 首先,用户的需求是表格可拖拽、可编辑,包含输入框和下拉选择框,并且可以增加和删除行。根据引用[^1],React Ant Design可以通过使用dnd-kit实现拖拽,而编辑功能需要状态管理和自定义渲染。引用[^2]提到了Element UI中使用多个表单实例进行校验,每个表单独立验证。 我需要分步骤说明两种框架的实现方式。对于React Ant Design,首先安装必要的库,然后创建可编辑的单元格组件,处理拖拽逻辑,最后整合到表格中。代码示例需要展示状态管理和事件处理,比如保存和删除行。同时,要提到性能优化的注意事项。 对于Element UI,可能需要使用el-table组件,结合el-form和表单验证。每个行作为独立的表单,在保存时遍历所有表单实例进行验证。这里需要给出Vue的代码示例,包括模板和脚本部分,展示如何绑定数据和校验规则。 最后,生成相关问题,帮助用户进一步探索,比如性能优化、数据持久化、复杂校验等。要确保问题覆盖用户可能关心的其他方面。 需要注意的是,代码部分要正确,使用合适的语法,并且注释清晰。同时,按照用户的要求,行内公式用$...$,但在这个问题中可能用不到数学公式,但需要保持LaTeX格式的正确。不过当前问题主要涉及代码和组件,可能不需要数学表达式,但还是要遵循格式要求。 总结步骤: 1. 分框架(React Ant Design和Element UI)介绍实现方法。 2. 每个框架的步骤包括安装依赖、组件结构、状态管理、事件处理。 3. 提供代码示例,确保语法正确。 4. 引用用户提供的引用内容,自然标注来源。 5. 生成相关问题,覆盖扩展功能和优化。</think>### 如何实现可编辑表格功能? #### 一、实现方式概述 可编辑表格的核心是 **动态数据绑定** 和 **交互事件处理**,结合前端框架(如React、Vue)的组件化能力实现。以下是两种主流框架的实现方法: --- #### 二、React Ant Design 实现 ##### 1. 核心依赖 - `antd`:提供表格组件 - `@dnd-kit/core`:实现拖拽功能 - `@dnd-kit/sortable`:支持排序 ##### 2. 关键步骤 1. **状态管理**:使用`useState`存储表格数据 ```javascript const [dataSource, setDataSource] = useState(initialData); ``` 2. **可编辑单元格组件** 通过条件渲染切换输入框/下拉框: ```jsx const EditableCell = ({ isEditing, inputType, value, onSave }) => { if (isEditing) { return inputType === 'select' ? ( <Select onChange={(v) => onSave(v)} defaultValue={value} /> ) : ( <Input defaultValue={value} onBlur={(e) => onSave(e.target.value)} /> ); } return value; }; ``` 3. **拖拽实现** 使用`useSortable`钩子绑定拖拽事件: ```jsx const { attributes, listeners, setNodeRef } = useSortable({ id: rowKey }); ``` 4. **完整示例代码** [查看完整实现代码](https://codesandbox.io/s/react-antd-editable-table-dnd-示例链接) ##### 3. 注意事项 - 数据更新时使用不可变数据模式 - 复杂校验可结合`form.getFieldError` --- #### 三、Element UI(Vue)实现 ##### 1. 核心方案 - 每行独立表单实现校验 - `el-table` + `el-form`嵌套使用 ##### 2. 关键代码 ```vue <template> <el-table :data="tableData"> <el-table-column prop="name"> <template #default="{ row, $index }"> <el-form :ref="`form${$index}`" :model="row"> <el-form-item :rules="[{ required: true, message: '姓名必填' }]" prop="name" > <el-input v-model="row.name" /> </el-form-item> </el-form> </template> </el-table-column> </el-table> <el-button @click="validateAll">保存</el-button> </template> <script> export default { methods: { async validateAll() { const results = await Promise.all( this.tableData.map((_, i) => this.$refs[`form${i}`][0].validate() ) ); if (results.every(valid => valid)) { // 提交数据 } } } } </script> ``` ##### 3. 优化技巧 - 使用`async/await`处理异步校验 - 缓存表单引用提升性能 --- #### 四、功能扩展建议 | 功能 | 实现方案 | |------------|-----------------------------| | 数据持久化 | 对接后端API或localStorage | | 复杂校验 | 自定义校验规则(如正则匹配)| | 批量编辑 | 添加全选/批量操作按钮 | ---
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值