react-dnd 拖拽排序

摘要:
一开始,我刚刚完成了表单组件的定制。让我们分享一下拖放排序。Index+1:Index,0,dragRow)setList}//DragSortItemComponent组件是一个通用的排序组件,因此需要在父组件中定义useDrop来更改数据。它必须附加到父divconst[,drop]=useDropconstItemDragClass=˃{if(itemClass.value!

开始

最近刚刚做完自定义表单的组件,分享一下拖拽排序。

效果图

react-dnd 拖拽排序第1张

react-dnd使用说明

必须是这样格式的,不然会报 找不到上下文

<DndProvider backend={HTML5Backend}>
   <useDrop>
      <useDrag></useDrag>
   </useDrop>
</DndProvider>

准备工作

官方文档

https://react-dnd.github.io/react-dnd/about

安装react-dnd、react-dnd-html5-backend

npm install react-dnd react-dnd-html5-backend

开始开发

项目是基于ts的,不需要可自行删除

定义父组件

const Drag:React.FC<{}> = props => {
  return (
    <div className="drag-wrapper">
      {/* DndProvider组件提供了react-dnd的功能,必须通过backend绑定HTML5Backend*/}
      <DndProvider backend={HTML5Backend}>
        <DragSortComponent/>
      </DndProvider>
    </div>
  )
}

export default Drag

定义内容组件

const DragSortComponent:React.FC<{}> = props => {
  const [list,setList] = useState<{id:number,name:string}[]>(List)
  const [itemClass, setItemClass] = useState<{ key: number | null; value: string }>({
    key: null,
    value: '',
  })
  // 拖拽后的值
  const sortItems = useRef<{ dragRow: any; placeRow: any; posi: string }>({
    dragRow: {},
    placeRow: {},
    posi: '',
  })
  // 拖拽结束后的方法
  const onDrop = (item: any, monitor: DropTargetMonitor) => {
    const { dragRow, placeRow, posi } = sortItems.current
    let _map: any[] = JSON.parse(JSON.stringify(list))
    let index1 = _map.findIndex(v => v.id === dragRow.id) // 拖拽的itemIndex
    _map.splice(index1, 1) // 先删掉拖拽的,在获取放置的
    let index = _map.findIndex(v => v.id === placeRow.id) // 放置的itemIndex
    if (index !== -1 && index1 !== -1) {
      _map.splice(posi === 'bottom' ? index + 1 : index, 0, dragRow)
      setList(() => _map)
    }
  }
  // DragSortItemComponent组件是通用排序组件,所以需要在父组件在定义一个useDrop,来改变数据 必须挂载在父级div
  const [, drop] = useDrop({
    accept: 'sort', // 必须和拖拽的accept一致
    drop: onDrop,
    collect: monitor => ({
      isOver: monitor.isOver({ shallow: true }),
      canDrop: monitor.canDrop(),
    }),
  })
  const onItemDragClass = (key:number,value:string) => {
    if (itemClass.value !== value) {
      setItemClass(() => {
        let data = { key, value }
        return data
      })
    }
  }
  const onSortItemChange = (dragRow: any, placeRow: any, posi: string) => {
    sortItems.current = { dragRow, placeRow, posi }
  }
  return (
    <div className="drag-sort-component-wrapper" ref={drop}>
      {
        list.map(v => (
          <DragSortItemComponent
            key={v.id}
            row={v}
            onItemDragClass={onItemDragClass}
            onSortItemChange={onSortItemChange}
            keyName="id"
          >
            <div className={['drag-item ',itemClass.key === v.id ? itemClass.value : ''].join(' ')}>{v.name}</div>
          </DragSortItemComponent>
        ))
      }
    </div>
  )
}

定义拖拽排序组件

/**
 * 通用拖拽排序的容器
 * @param row 当前行
 * @param onItemDragClass 拖拽过程的样式 top | bottom
 * @param onSortItemChange 拖拽结束后返回的值 dragRow 当前拖拽 placeRow 放置的,posi 位置 top | bottom
 * @param keyName 键名
 */
type IProps = {
  row: any,
  onItemDragClass: (key:number,value:string) => void,
  onSortItemChange: (dragRow: any, placeRow: any, posi: string) => void // 排序后
  keyName: string
}
const DragSortItemComponent:React.FC<IProps> = props => {
  const { row,onItemDragClass,onSortItemChange,keyName } = props
  const ref = useRef<HTMLDivElement>(null)
  /**
   * 拖拽容器
   */
  const [, drop] = useDrop({
    // 定义拖拽的类型
    accept: 'sort',
    drop: (item, monitor) => {
      const didDrop = monitor.didDrop()
      if (didDrop) {
        return
      }
    },
    canDrop: (item, mointor) => {
      // 阻止默认拖拽释放
      onItemDragClass(row[keyName], '')
      return false
    },
    hover: (item: any, monitor) => {
      const didHover = monitor.isOver({ shallow: true })
      if (didHover) {
        // 拖拽目标的id
        const dragIndex = item[keyName]
        // 放置目标id  可以用index | id 只要是number,数据里唯一的就可以
        const hoverIndex = row[keyName]
        // 如果一样不处理
        if (dragIndex === hoverIndex) {
          onItemDragClass(row[keyName], '')
          return
        }
        // 获取放置的位置
        const hoverBoundingRect = ref.current?.getBoundingClientRect() as DOMRect
        // 获取放置的Y轴中点
        const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2
        // 获取拖拽目标偏移量
        const clientOffset = monitor.getClientOffset() as XYCoord
        const hoverClientY = clientOffset.y - hoverBoundingRect.top
        if (dragIndex !== hoverIndex) {
          if (hoverMiddleY < hoverClientY) {
            onItemDragClass(row[keyName], 'bottom')
          } else {
            onItemDragClass(row[keyName], 'top')
          }
          // 如果不做成通用拖拽容器,把参数存起来,把这个放在useDrag的end方法里,
          onSortItemChange(item, row, hoverMiddleY < hoverClientY ? 'bottom' : 'top')
        }
      }
    },
    collect: monitor => ({
      isOver: monitor.isOver({ shallow: true }),
      canDrop: monitor.canDrop(),
    }),
  })
  /**
   * 定义拖拽
   * isDragging 是否拖拽
   */
  const [{ isDragging }, drag] = useDrag({
    item: { ...row, type: 'sort'},
    end: () => {
      // onSortItemChange(item, row, hoverMiddleY < hoverClientY ? 'bottom' : 'top')
    },
    collect: monitor => ({
      isDragging: monitor.isDragging(),
      didDrop: monitor.isDragging(),
    }),
  })
  drop(drag(ref))
  return (
    <div ref={ref} style={{ opacity: isDragging ? 0 : 1 }}>
      {props.children}
    </div>
  )
}

github地址

https://github.com/GeFei-someone/drag-sort

免责声明:文章转载自《react-dnd 拖拽排序》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SQLite剖析之临时文件、内存数据库mysql8.0 初始化数据库及表名大小写问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

【转】用Python实现各种排序算法

以下代码均为python3版本的代码 # 冒泡排序 # 比较相邻的元素大小,将小的前移,大的后移,就像水中的气泡一样,最小的元素经过几次移动,会最终浮到水面上。 def bubbleSort(list): if list != None: if len(list) ==1: pass...

签名:实现参数字典排序,然后拼接为url参数形式

在很多地方请求参数需要做处理例如: 步骤 1.参数字典排序。 2.拼接字符。 /// <summary> ///生成签名 /// </summary> /// <param name="paramlst">参数列表</param>...

Django Admin Cookbook-9如何启用对计算字段的排序

9.如何启用对计算字段的排序? 通常,Django会为模型属性字段,自动添加排序功能。当你添加计算字段时,Django不知道如何执行order_by,因此它不会在该字段上添加排序功能。 如果要在计算字段上添加排序,则必须告诉Django需要排序的内容。你可以通过在在计算字段方法中设置admin_order_field属性来执行此操作 。 我们从上一章(如何...

Java常用排序算法+程序员必须掌握的8大排序算法+二分法查找法

Java 常用排序算法/程序员必须掌握的 8大排序算法  本文由网络资料整理转载而来,如有问题,欢迎指正!  分类:  1)插入排序(直接插入排序、希尔排序)  2)交换排序(冒泡排序、快速排序)  3)选择排序(直接选择排序、堆排序)  4)归并排序  5)分配排序(基数排序)  所需辅助空间最多:归并排序  所需辅助空间最少:堆排序  平均速度最快:快...

容器知识的重点总结

什么是容器 数组也是一种容器,可以存放对象或基本数据类型,数组的劣势在于不灵活,容器需要事先定义好,不能随着需求而改变而扩容。而容器则可以随时扩容来装对象,容器也称为集合。 容器的结构 单例集合 将数据一个一个的进行存储 双例集合 基于 key 和 value 的结构存储数据 Collection 接口 LIst接口:有序,可重复 ArrayList 容...

【Java】自定义排序器StringComparator

功能:字符串直接排序,常常出现‘11’,‘12’等排在10后面缺在2,3等前面的情况,该排序器能在字符串能合理转化为数字时按数字排序,从而能使数字字符串按真正的顺序来,11,12等不再插队;党字符串不能合理转化为数字时便仍然按字符串排序。 定义: import java.util.Arrays; import java.util.Collections;...