react 实现表格列表拖拽排序的示例
问题描述
在项目开发中,遇到这样一个需求:需要对表格里面的数据进行拖拽排序。
效果图如下所示:
思路
安装两个插件:
- react-sortable-hoc (或者 react-beautiful-dnd)
- array-move
npm install --save react-sortable-hoc npm install --save array-move
解析
1. react-sortable-hoc
react-sortable-hoc
是一组 react
高阶组件(参数或返回值为函数),用于实现拖动排序功能,可以将任何列表转换为动画,可访问和触摸友好的可排序列表。可以和现有组件集成,支持拖动手柄、自动滚动、锁定轴和操作事件等功能,有着流程的动画效果。可水平、垂直拖动。
react-sortable-hoc 的使用:
react-sortable-hoc
提供了两个特别重要的API
- SortableContainer :是所有可拖拽排序元素的容器
- SortableElement :是每个要拖拽排序元素的容器
- SortableHandle :是定义拖拽手柄的容器
import { SortableHandle } from 'react-sortable-hoc'; import { MenuOutlined } from '@ant-design/icons'; const DragHandle = SortableHandle(() => <MenuOutlined style={{ cursor: 'grab', color: '#999' }} />) { title: '拖动排序', dataIndex: 'sort', width: 120, align: 'center', className: 'drag-visible', editable: false, render: () =>{ if (editable) return <DragHandle />; return <span>禁止拖动</span> }, },
SortableHandle 就是指下面的箭头部分
SortableElement
提供了一个 index
属性来进行对每个要拖拽元素的排序
SortableContainer
提供一个方法 onSortEnd
,这个方法可以解构两个形参:{ oldIndex , newIndex }
,一个是拖拽元素的标记,一个是将要放的地方的标记。
最后在使用 arrayMoveImmutable
交换数组的位置。
axis 表示拖拽的方向,x 是水平拖拽,y 是垂直拖拽,默认是垂直拖拽
2. array-move
array-move
其实就是一个 API,它的主要作用是用来交换数组中元素的位置。
看下面的实例:
// 在tsx文件中 import React, { useEffect } from 'react'; import { arrayMoveImmutable } from 'array-move'; const Index = () => { useEffect(() => { let arr = ['a', 'b', 'c'] let result = arrayMoveImmutable(arr, 1 , 2) console.log(result) // 结果输入为: [ 'a', 'c', 'b' ] }) } export default Index
使用
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc'; import { arrayMoveImmutable } from 'array-move'; // 定义拖拽的table 容器 const DragTableContainer = SortableContainer((props) => <tbody {...props}>) // 定义 拖拽的 行 const DragTableItem = SortableElement((props) => <tr {...props}>) // 定义拖拽手柄 const DragHandle = SortableHandle(() => ( <MenuOutlined title='拖拽排序' /> )) // 表格排序方法 const onSortEnd = ({oldIndex, newIndex}: {oldIndex: number; newIndex: number }) => { if (oldIndex !== newIndex) { const newData: any[] = arrayMoveImmutable(([] as any[]).concat(dataSource), oldIndex, newIndex).filter((el: any) => !!el); handleAllSave(newData) // 父组件传过来的方法,用于更新表格第一列的序号 } } // 所有可拖拽排序元素的容器 // DragTableContainer 是上面通过 SortableContainer 定义的拖拽的table 容器 // useDragHandle 参数,意思是: 使用行把手拖拽行排序 // disableAutoscroll 参数,禁止自动滚动 // helperClass 参数,可修改拖拽样式 // onSortEnd `SortableContainer` 提供的一个方法,这个方法可以解构两个形参:`{ oldIndex , newIndex }`,一个是拖拽元素的标记,一个是将要放的地方的标记,用于表格拖拽排序 const DraggableContainer = (props: any) => <DragTableContainer useDragHandle disableAutoscroll helperClass="row-dragging" onSortEnd={onSortEnd} {...props}/> // 定义 拖拽的 行 // DraggableBodyRow 返回的是由 SortableItem 包裹的每一行元素 const DraggableBodyRow = ({ className, style, ...restProps}: any) => { const index = dataSource.findIndex((x: any) => x.orderNum === restProps['data-row-key']); return (<SortableItem index={index} {...restProps} />) } // ---------------------------------------------------------------------------------------- // ---------------------------------------------------------------------------------------- // 封装的子组件 const EditableTable = (props: any) => { let { title = '', subtitle = '', columns, rowClassName = () => 'editable-row', dataSource, handleSave, handleAllSave, rowKey, placeholder, clickRow, loading = false, scroll } = props; const styles = { tabletitle: { fontWeight: 800, color: '#0095ff', fontSize: '16px' }, subtitle: { color: '#000000', fontSize: '12px' }, }; columns = columns.map((col: any) => { if (!col.editable) { return col; } return { ...col, onCell: (record: any) => ({ record, isRowDisable: col.isRowDisable, isNumber: col.isNumber, editable: col.editable, editdisable: col.editdisable, dataIndex: col.dataIndex, title: col.title, handleSave: handleSave, formRules: col.rules, placeholder: col?.placeholder, precision: col?.precision, min: col?.min, step: col?.step, max: col?.max, formatter: col?.formatter, parser: col?.parser, }), }; }); /** * 表格行属性 * @param record 表格每行的数据 * @returns */ const onRow = (record: any) => { return { onClick: clickRow ? () => clickRow(record) : undefined, } } const onSortEnd = ({oldIndex, newIndex}: {oldIndex: number; newIndex: number }) => { if (oldIndex !== newIndex) { const newData: any[] = arrayMoveImmutable(([] as any[]).concat(dataSource), oldIndex, newIndex).filter((el: any) => !!el); handleAllSave(newData) } } const DraggableContainer = (props: any) => <SortableBody useDragHandle disableAutoscroll helperClass="row-dragging" onSortEnd={onSortEnd} {...props}/> const DraggableBodyRow = ({ className, style, ...restProps}: any) => { const index = dataSource.findIndex((x: any) => x.orderNum === restProps['data-row-key']); return (<SortableItem index={index} {...restProps} />) } return ( <Fragment> <div style={{ display: 'flex', marginBottom: '6px' }}> <Table className="wrap" style={{ width: '100%' }} locale={{ emptyText: '暂无数据' }} components={{ body: { wrapper: DraggableContainer, row: DraggableBodyRow, // cell: EditableCell } }} rowClassName={rowClassName} bordered dataSource={dataSource} columns={columns} pagination={false} rowKey='orderNum' scroll={scroll || { y: 500 }} onRow={onRow} loading={loading} /> </div> </Fragment> ); }; export default memo(EditableTable);
到此这篇关于react 实现表格列表拖拽排序的示例的文章就介绍到这了,更多相关react 表格列表拖拽排序内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
详解开发react应用最好用的脚手架 create-react-app
本篇文章主要介绍了详解开发react应用最好用的脚手架 create-react-app,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧2018-04-04react基于Ant Desgin Upload实现导入导出
本文主要介绍了react基于Ant Desgin Upload实现导入导出,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧2024-01-01React 中如何将CSS visibility 属性设置为 hidden
这篇文章主要介绍了React中如何将CSS visibility属性设置为 hidden,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下2023-05-05React报错之Parameter event implicitly has a
这篇文章主要为大家介绍了React报错之Parameter event implicitly has an any type,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2022-08-08React Native按钮Touchable系列组件使用教程示例
这篇文章主要为大家介绍了React Native按钮Touchable系列组件使用教程示例,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪2023-11-11
最新评论