react 实现表格列表拖拽排序的示例

 更新时间:2023年02月01日 08:25:43   作者:小刘加油!  
本文主要介绍了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.forwardRef传递泛型参数

    使用React.forwardRef传递泛型参数

    这篇文章主要介绍了使用React.forwardRef传递泛型参数方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • react中value与defaultValue的区别及说明

    react中value与defaultValue的区别及说明

    这篇文章主要介绍了react中value与defaultValue的区别及说明,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-05-05
  • react+antd动态增删表单方式

    react+antd动态增删表单方式

    这篇文章主要介绍了react+antd动态增删表单方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-01-01
  • react+redux的升级版todoList的实现

    react+redux的升级版todoList的实现

    本篇文章主要介绍了react+redux的升级版todoList的实现,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-12-12
  • 解决React报错JSX element type does not have any construct or call signatures

    解决React报错JSX element type does not have any construct

    这篇文章主要为大家介绍了解决React报错JSX element type does not have any construct or call signatures,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-12-12
  • 在 React 中如何从状态数组中删除一个元素

    在 React 中如何从状态数组中删除一个元素

    这篇文章主要介绍了在 React 中从状态数组中删除一个元素,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-03-03
  • React常见跨窗口通信方式实例详解

    React常见跨窗口通信方式实例详解

    这篇文章主要为大家介绍了React常见跨窗口通信方式实例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-10-10
  • react.js框架Redux基础案例详解

    react.js框架Redux基础案例详解

    这篇文章主要介绍了react.js框架Redux基础案例详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下
    2021-09-09
  • React使用有限状态机的实现示例

    React使用有限状态机的实现示例

    本文主要介绍了React使用有限状态机的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-05-05
  • 使用Redux处理异步问题

    使用Redux处理异步问题

    这篇文章主要介绍了使用Redux处理异步问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-03-03

最新评论