美文网首页
React - 封装带拖拽操作的FormList

React - 封装带拖拽操作的FormList

作者: 网恋被骗二块二 | 来源:发表于2023-02-10 09:56 被阅读0次

安装

使用到的依赖是: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 封装,能够达到复用目的

封装思路

  1. 了解 FormList 的用法
  2. 了解 react-sortable-hoc 拖拽需要的相关实现
    除开本身的 onSortEnd 外,还有 FormList 自带的 move 方法,所以 SortableContainer 在 FormList 的内部
  3. 考虑 children 区域自定义性和 children 能够使用的属性
  4. 考虑拖拽手柄项的自定义性
  5. ……

步骤

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,参考了用法和一部分源码后,明白了是怎么用的。

仅作记录

相关文章

网友评论

      本文标题:React - 封装带拖拽操作的FormList

      本文链接:https://www.haomeiwen.com/subject/ovuzhdtx.html