【Ant Design+React DnD】模态框里的拖拽排序组件

这是一个模态框里带有拖拽排序的组件(获取链接:github),排序完成之后可以更新父组件里的排序数据,组件的图形界面如下:

dragTableIcon.png

dragTable.png

主要用到的前端库有:Ant Design、React DnD.

此组件的结构图如下:


拖拽排序组件结构图.png

上图中,AntDesign的组件:SettingOutlined、Modal
ReactDnD的组件:DnDProvider,
自己设计的组件:DragSortingTable、DragableBodyRow

此组件的实现思路如下:

  1. 父组件DragSortingTableModalBtn下有最外层的2个组件:
  • SettingOutlined设置icon按钮
  • Modal模态对话框
    父组件里控制排序数据变量data以及拖拽DragableBodyRow触发的事件moveRow,调用此父组件的上层组件则控制模态对话框的显示与隐藏。
class DragSortingTableModalBtn extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      data: props.dataList||[] //排序数据变量
    };
  }

  moveRow(dragIndex, hoverIndex) { //拖拽事件
    let { data } = this.state;
    const dragRow = data[dragIndex]; 
    let newData = update(data, {
      $splice: [
        [dragIndex, 1],
        [hoverIndex, 0, dragRow],
      ],
    });
    
    this.setState({
      data: newData
    });
  }
  render() {}
}
  1. DragSortingTable会在DndProvider组件下加载出拖拽元素组件DragableBodyRow,而一系列的拖拽事件处理是在DragableBodyRow内进行处理。
const DragSortingTable = ({ data, moveRow }) => {
  const renderRow = (item, index) => {
    return (
      <DragableBodyRow
        key={item.key}
        index={index}
        id={item.key}
        text={item.text}
        moveRow={moveRow}
      />
    )
  };
  return (
    <div className="DragSortingTable">
      <DndProvider backend={HTML5Backend}>
      { data.map((item, i) => renderRow(item, i)) }
      </DndProvider>
    </div>
  );
}
  1. DragableBodyRow内部处理拖拽行为事件,而拖拽的关键处理是由React-DnDuseDrag, useDrop进行处理的,简单介绍下useDrag以及useDrop的语法(官网链接):
    useDrag:
    参数:
  • spec 一个特殊对象Object或创建特殊对象Object的方法。特殊对象Object的说明参见下方。
  • deps 一个用作存储的依赖数组。
    返回值数组:
  • [0] - Collected Propscollect方法返回的对象数据object。若collect方法未定义,则返回的是空对象。
  • [1] - DragSource Ref:拖拽源的连接器方法。此方法必须依附于DOM元素的拖拽部分。
  • [2] - DragPreview Ref:拖拽预览的连接器方法。此方法必须依附于DOM元素的预览部分。

特殊对象Object成员:

  • type:必须。类型为字符串,拖拽目标的注册类型,只有类型相同才会响应。
  • item:必须(object或function) 拖拽对象的内部数据定义
  • previewOptions:可选。预览项
  • options:可选。拖拽的操作行为对象数据
    • dropEffect:拖拽的影响:move或copy是可选项
  • end(item, monitor):可选。当拖拽停止时,此方法会被调用。
  • canDrag(monitor):可选。用此方法定义拖拽在当前是否被允许。
  • isDragging(monitor):可选。拖拽时的方法。
  • collect:可选。收集方法。返回一个对象数据注入你的组件。

useDrop:
参数:

  • spec 一个特殊对象Object或创建特殊对象Object的方法。特殊对象Object的说明参见下方。
  • deps 一个用作存储的依赖数组。
    返回值数组:
  • [0] - Collected Propscollect方法返回的对象数据object。若collect方法未定义,则返回的是空对象。
  • [1] - DropTarget Ref:拖动源的连接器方法。此方法必须依附于DOM元素的拖动部分。

特殊对象Object成员:

  • accept:必须。类型为字符串,数组或方法,拖动目标的接受类型,只有类型相同才会响应。
  • options:可选。
  • drop(item, monitor):可选。当兼容目标item被拖动到目标上,此方法会被调用。
  • hover(item, monitor):可选。当item悬浮到组件上,此方法会被调用。
  • canDrag(monitor):可选。用此方法定义拖动在当前是否被允许。
  • collect:可选。收集方法。返回一个对象数据注入你的组件。

组件DragableBodyRow对于useDrag以及useDrop的处理如下:

const DragableBodyRow = ({ id, text, index, moveRow }) => {
  const ref = useRef();
  const [{ isOver, dropStyle }, drop] = useDrop({
    //定义拖拽的类型
    accept: ItemType,    
    collect: monitor => {
      const { index: dragIndex } = monitor.getItem() || {};
      // 如果拖拽目标和放置目标相同的话,停止执行
      if (dragIndex === index) {
        return {};
      }

      return {
        isOver: monitor.isOver(),
        dropStyle: dragIndex < index ? dropDownStyle : dropUpStyle,
      };
    },
    drop: item => {
      const dragIndex = item.index;
      const hoverIndex = index;
      moveRow(dragIndex, hoverIndex);
    }
  },
  [index]
  );
  let _dropStyle = isOver ? dropStyle : {};

  const [{ opacity }, drag] = useDrag({
    type: ItemType,
    item: { id, index },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
      opacity: monitor.isDragging() ? 0.5 : 1
    })
  },
  [index]
  );
  drag(drop(ref));

  return (
    <div 
      ref={ref} 
      style={{ ...style, opacity, ..._dropStyle }}
    >
      <div className='row-item' dangerouslySetInnerHTML={{ __html: text }}></div>
    </div>
  )
}

以上就是对于模态框里的拖拽排序组件的全部介绍,完整代码请前往github获取。

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

推荐阅读更多精彩内容