react 好用的排序插件--列表支持

好用的拖拽插件

react-dnd(以前做自定义拖拽时常用的 自由度高 但复杂度也偏高)

react-sortable-hoc(只支持列表 若是列表使用 实为上上之选)

官方地址:https://github.com/clauderic/react-sortable-hoc

 

修改拖拽样式 添加helperClass样式 绑定在 const SortableList = SortableContainer(()=>{}) 上

You can provide a class you'd like to add to the sortable helper to add some styles to it

你可以提供一个你想添加到 sortable 助手的类来添加一些样式

helperClass="custom-row-dragging"

 

关键方法--通过新老索引实现拖拽

const onSortEnd = (oldIndex: number, newIndex: number) => {
    if (oldIndex !== newIndex) {
      // 逻辑处理
    }
  };

  

手写列表:

 

 

import React from 'react';
import { observer } from 'mobx-react';
import { SortableContainer, SortableElement } from 'react-sortable-hoc';
import { arrayMoveImmutable } from 'array-move';
import { Input, Button } from 'antd';
import AppIcon from '@/components/AppIcon';
import styles from '../../index.module.less';

const SortableItem = SortableElement(
  (props: { item: two_level_class; idx: number; setData: Function }) => {
    const { item, idx, setData } = props;
    const { id, name, sort, customId } = item;
    return (
      <div className={styles['list-item']} style={{ zIndex: 1001 }}>
        <AppIcon type="sort" className={styles['sort-icon']} />
        <span className={styles['sort-num']}>{idx + 1}</span>
        <Input
          placeholder="请输入"
          value={name}
          onChange={e =>
            setData('subMenuModels', e.target.value, id || customId)
          }
        />
        <Button
          icon={<AppIcon type="delete" className={styles['icon']} />}
          onClick={() => setData('delete', id || customId || '')}
          type="text"
        ></Button>
      </div>
    );
  },
);

const SortableList = SortableContainer(
  ({ items, setData }: { items: two_level_class_list; setData: Function }) => {
    return (
      <ul>
        {items.map((item, index) => (
          <SortableItem
            item={item}
            idx={index}
            setData={setData}
            key={`item-${item.id}`}
            index={index}
          />
        ))}
      </ul>
    );
  },
);
interface IProps {
  list: two_level_class_list;
  setList: Function;
  setData: Function;
}
const Index = ({ list, setList, setData }: IProps) => {
  const onSortEnd = ({
    oldIndex,
    newIndex,
  }: {
    oldIndex: number;
    newIndex: number;
  }) => {
    setList((value: ClassItem) => {
      return {
        ...value,
        subMenuModels: arrayMoveImmutable(list, oldIndex, newIndex),
      };
    });
  };
  return (
    <SortableList
      helperClass={styles['custom-row-dragging']}
      items={list}
      onSortEnd={onSortEnd}
      setData={setData}
    />
  );
};

export default observer(Index);

  

table:

 

 

// 一级分类排序(table)
import React from 'react';
import { observer } from 'mobx-react';
import { Table, Button } from 'antd';
import {
  SortableContainer,
  SortableElement,
  SortableHandle,
} from 'react-sortable-hoc';
import AppIcon from '@/components/AppIcon';

const DragHandle = SortableHandle(() => <AppIcon type="sort" />);
const SortableItem = SortableElement((props: any) => <tr {...props} />);
const SortableBody = SortableContainer((props: any) => <tbody {...props} />);
interface IProps {
  onDelete: Function;
  handleOpenEdit: Function;
  onClassDrag: Function;
  classlist: ClassList;
}
const Index = (props: IProps) => {
  const { handleOpenEdit, onDelete, classlist, onClassDrag } = props;

  const columns = [
    {
      title: '',
      dataIndex: 'index',
      width: 30,
      className: 'custom-drag-visible',
      render: () => <DragHandle />,
    },
    {
      title: '排序',
      dataIndex: 'sort',
    },
    {
      title: '一级分类',
      dataIndex: 'name',
    },
    {
      title: '二级分类',
      dataIndex: 'subMenuModels',
      render: (list: two_level_class_list) => list.map(m => m.name).join('、'),
    },
    {
      title: '操作',
      dataIndex: 'id',
      editable: true,
      fixed: 'right',
      render: (text: string, record: ClassItem) => {
        return (
          <div style={{ backgroundColor: 'transparent' }}>
            <Button type="text" onClick={() => handleOpenEdit(record)}>
              编辑
            </Button>
            <Button type="text" onClick={() => onDelete(record)}>
              删除
            </Button>
          </div>
        );
      },
    },
  ];

  const onSortEnd = (oldIndex: number, newIndex: number) => {
    if (oldIndex !== newIndex) {
      const sourceMenuId = classlist[oldIndex].id;
      const targetMenuId = classlist[newIndex].id;
      onClassDrag({ sourceMenuId, targetMenuId });
    }
  };

  const DraggableContainer = (props: any) => {
    return (
      <SortableBody
        useDragHandle
        disableAutoscroll
        helperClass="custom-row-dragging"
        onSortEnd={({
          oldIndex,
          newIndex,
        }: {
          oldIndex: number;
          newIndex: number;
        }) => onSortEnd(oldIndex, newIndex)}
        {...props}
      />
    );
  };

  const DraggableBodyRow = ({ ...restProps }) => {
    const index = classlist.findIndex(
      x => x.index === restProps['data-row-key'],
    );
    return <SortableItem index={index} {...restProps} />;
  };

  return (
    <Table
      pagination={false}
      dataSource={classlist}
      columns={columns}
      rowKey="index"
      components={{
        body: {
          wrapper: (props: any) => DraggableContainer(props),
          row: (props: any) => DraggableBodyRow(props),
        },
      }}
    />
  );
};

export default observer(Index);

 

坑点:(不确定是不是sortable引起的)

1、弹框里面div点击事件无法触发,改用button

2、拖拽是脱离了文档流 又因为 弹框也是脱离了文档流 所以拖拽样式被弹框遮住了 可用z-index覆盖

posted @ 2022-04-27 18:32  水晴  阅读(1268)  评论(0)    收藏  举报