问题描述
在项目开发中,遇到这样一个需求:需要对表格里面的数据进行拖拽排序。
效果图如下所示:
思路
安装两个插件:
- 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,
}),
};
});
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 表格列表拖拽排序内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!