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覆盖

浙公网安备 33010602011771号