React - 封装带拖拽操作的FormList

安装

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

仅作记录

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352

推荐阅读更多精彩内容