安装
使用到的依赖是:react-sortable-hoc
npm i react-sortable-hoc
使用
import { SortableContainer, SortableElement, SortableHandle } from 'react-sortable-hoc';
SortableContainer - 拖拽根容器
SortableElement - 拖拽项容器
SortableHandle - 拖拽手柄(需要 useDragHandle)
示例
// 创建拖拽柄
const DragHandle = SortableHandle(() => (
<MenuOutlined style={{ cursor: 'grab', color: '#999' }} />
));
// 拖拽项容器
const SortableItem = SortableElement((props: React.HTMLAttributes<HTMLDivElement>) => (
<div {...props} />
));
// 创建拖拽根容器
const SortableBody = SortableContainer((props: React.HTMLAttributes<HTMLDivElement>) => (
<div {...props} />
));
需求
基于 FormList 封装,能够达到复用目的
封装思路
- 了解 FormList 的用法
- 了解 react-sortable-hoc 拖拽需要的相关实现
除开本身的 onSortEnd 外,还有 FormList 自带的 move 方法,所以 SortableContainer 在 FormList 的内部 - 考虑 children 区域自定义性和 children 能够使用的属性
- 考虑拖拽手柄项的自定义性
- ……
步骤
ps:省略 import 引入
步骤1
基本的组件注册
const DragFormList = () => { return () }
export default DragFormList;
步骤2
因为是基于 FormList 封装的,因此需要先实现一个 FormList
const DragFormList = () => { return (
<>
<Form.Item {...formListProps} >
{(fields, { add, remove, move }) => fields.map((({ key, name, ...restFiled }, index) => <></>)}
<Form.Item>
</>
) }
export default DragFormList;
步骤3
根据 FormList 的结构性,将拖拽组件的 SortableContainer 和 SortableElement 放到合适的位置
react-sortable-hoc 中 SortableContainer - onSortEnd 中对我们有用的参数分别是 oldIndex, newIndex 而这两个参数源于 SortableElement 上绑定的 index
(ps:react-sortable-hoc 使用场景好像必须是数组循环项 )
而刚好 FormList 的 move 也需要这两个参数,所以 SortableContainer 必定在 FormList 的内部
const DragFormList = () => { return (
<>
<Form.Item {...formListProps} >
{(fields, { add, remove, move }) =>
<SortableContainer>
fields.map((({ key, name, ...restFiled }, index) =>
<SortableElement index={index} />
</SortableContainer>
)}
<Form.Item>
</>
) }
export default DragFormList;
步骤4
children 可能会需要依赖内部的一些 state 或者 function,所以我是考虑将 children 作为函数形式 () => <></>
来实现,这样便可以做到参数的传递
const DragFormList = () => { return (
<>
<Form.Item {...formListProps} >
{(fields, { add, remove, move }) =>
<SortableContainer>
fields.map((({ key, name, ...restFiled }, index) => {
const props = {} // 需要给子组件使用的 state 和 function
return <SortableElement index={index} >
children(props)
</SortableElement>
}
</SortableContainer>
)}
<Form.Item>
</>
) }
export default DragFormList;
步骤5
自定义拖拽手柄,总不可能让使用者只能用一种样式的手柄吧?这也太不智能了
const CustomizeDragHandle: React.FC<CustomizeDragHandleProps> = ({ EleDragHandle }) => {
let DragHandle;
if (EleDragHandle) {
DragHandle = SortableHandle(() => EleDragHandle);
} else {
DragHandle = SortableHandle((props: any) => (
<MenuOutlined style={{ cursor: 'grab', color: '#999' }} {...props} />
));
}
return <DragHandle />;
};
步骤6
封装组件 Props 其他的补充,如 add 、或者 react-sortable-hoc 属性等的定义,这里就不多讲了
总结
这只是基于 FormList 的封装,也可以基于别的场景封装,如果不是 FormList 这种自带 Array 和 function 的组件,甚至是自定义的组件,那么一定需要你在内部创建 Array 和对应的 add、move、remove、copy、insert 等方法
其次就是注意结构,Array.map 的是 SortableElement;SortableContainer 不在循环体内;onSortEnd 要能够正确调用到 function;SortableHandle 要提供给用户自定义(也可以不使用);SortableContainer - helperClass 是拖拽时 react-sortable-hoc 复制的元素样式,在控制台可以看到。
这个也不难,主要是第一次封装时对我自己来说难点在于如何把组件内的东西给children用,不过也还好是FormList,参考了用法和一部分源码后,明白了是怎么用的。
仅作记录