React implements table list drag and drop sorting

Problem Description

In project development, I encountered such a requirement: the data in the table needs to be dragged and sorted.

The effect diagram is as follows:

insert image description here

train of thought

Install two plugins:

  • react-sortable-hoc (或者 react-beautiful-dnd)
  • array-move
npm install --save react-sortable-hoc
npm install --save array-move

analyze

1. react-sortable-hoc

react-sortable-hocIs a set of reacthigher-order components (parameters or return values ​​are functions), used to implement the drag sorting function, which can convert any list into an animated, accessible and touch-friendly sortable list. It can be integrated with existing components, supports functions such as dragging handles, automatic scrolling, locking axes, and operating events, and has process animation effects. Can be dragged horizontally and vertically .

Use of react-sortable-hoc:

react-sortable-hocTwo particularly important APIs are provided

  • SortableContainer : is the container for all draggable sortable elements
  • SortableElement : is the container for each element to be dragged and sorted
  • SortableHandle : is the container that defines the drag handle
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 refers to the arrow part below

insert image description here

SortableElementA indexproperty to sort each element to be dragged

SortableContainerProvide a method onSortEndthat can deconstruct two formal parameters: { oldIndex , newIndex }, one is the mark of the dragged element, and the other is the mark of the place to be dropped.

Finally, use to arrayMoveImmutableswap the position of the array.

axis indicates the dragging direction, x is horizontal dragging, y is vertical dragging, the default is vertical dragging

2. array-move

array-moveIn fact, it is an API, and its main function is to exchange the position of elements in the array.

See the example below:

// 在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

use

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);


おすすめ

転載: blog.csdn.net/qq_41131745/article/details/128429108