(react实现拖拽)拖拽的整体主要代码 ——拖拽完整代码

拖拽的整体主要代码 ——拖拽完整代码

拖拽的整体主要代码

​ 实现本次拖拽的效果的主要代码如下

import React,{useRef,useEffect,useState} from 'react'
import './index.scss'
const prefixCls = 'drag'

interface distanceState {
  left: number,
  right: number,
  top: number,
  bottom: number,
  width: number,
  height: number
}

const useDistanceArr = (dragArrRef: any) => {
  const [distanceArr,setDistanceArr] = useState<distanceState[]>([])
  useEffect(()=>{
    if(dragArrRef && dragArrRef.current) {
      let dragArr = dragArrRef.current.querySelectorAll(`.${prefixCls}-item`)
      let newDistanceArr = []
      for(let dragItem of dragArr) {
        let itemDistance = dragItem.getBoundingClientRect()
        newDistanceArr.push(itemDistance)
      }
      setDistanceArr(newDistanceArr)
    }
  },[])
  return distanceArr
} 

const Drag = () => {
  const dragArrRef = useRef<any>()
  const distanceArr = useDistanceArr(dragArrRef)
  let timer: any | null = null
  // 做一个节流处理
  const showLine = (show: boolean,index?: any,direction?: string) => {
    if(!timer || !show) {
    timer = setTimeout(() => {
      // @ts-ignore
      const lineArr = document.getElementsByClassName('line')
      // @ts-ignore
      if(lineArr.length && lineArr[0].style) {
        for(let i=0;i<lineArr.length;i++) {
          // @ts-ignore
          lineArr[i].style.visibility = 'hidden'
        }
        if(show) {
          // @ts-ignore
          lineArr[index].style.visibility = 'visible'
          if(direction === 'left') {
            // @ts-ignore
            lineArr[index].style.left = '-25px'
          }else {
            // @ts-ignore
            lineArr[index].style.left = '125px'
          }
        }
        
      }
      timer = null
      clearTimeout(timer)
    },16.7)   
  }
  }
  useEffect(()=>{
    return () => {
      alert(2)
    }
  },[])

  const [dragArr,setDragArr] = useState([
    {
      name: '哈哈',
      backgroundColor: 'red',
    },
    {
      name: '呼呼',
      backgroundColor: 'blue',
    },
    {
      name: '嘿嘿',
      backgroundColor: 'green',
    },
    {
      name: '咯咯',
      backgroundColor: 'yellow',
    },
    {
      name: '球球',
      backgroundColor: 'skyblue',
    }
  ])
  // 记录鼠标在元素的位置
  let mouseInDrag = {
    leftWidth: 0,
    rightWidth: 0,
    topWidth: 0,
    bottomWidth: 0
  }

  const draging = (e:any,index: number) => {
    const {clientX,clientY} = e
    const {leftWidth,rightWidth} = mouseInDrag
    let endIndex,direction
    for(let i = 0;i < distanceArr.length;i++) {
      const {left,top,right,bottom} = distanceArr[i]
      if(left > (clientX - leftWidth) &&  i === 0) {
        endIndex = i
        direction = 'left'
        break 
      }else if(left < (clientX - leftWidth) && i === distanceArr.length - 1) {
        endIndex = i
        direction = 'right'
        break 
      }else if(left < (clientX - leftWidth) && distanceArr[i+1].left > (clientX - leftWidth) ) {
        // 判断向左还是向右
        // 向左运动,假设是2移动到1左边 这样0的左边< 1的左边> 实际就是第一个位置 需要 0+1 这样就是第一个位置
        if(i < index) {
          endIndex = i + 1
          direction = 'left'
        }else {
          // 向右运动, 假设是在2移动到3右边,这样3的左边< 4的左边> 实际就是第三个位置 需要 3 这样就是第三个位置
          endIndex = i
          direction = 'right'
        }
        break
      }
    }
    if(endIndex!==index && endIndex!==undefined) {
      showLine(true,endIndex,direction)
    }else {
      showLine(false)
    }
  } 
  
  const handleDragStart = (e: any,index: number) => {
    const {left,top,width,height} = distanceArr[index]
    const {clientX,clientY} = e
    mouseInDrag.leftWidth = clientX - left
    mouseInDrag.rightWidth = width - (clientX - left)
    mouseInDrag.topWidth = top - clientY
    mouseInDrag.bottomWidth = height - (top - clientY)
  }
  const handleDragLeave = (e: any,index: number) => {
  }
  const handleDragEnd = (e: any,index: number) => {
    const {clientX,clientY} = e
    const {leftWidth,rightWidth} = mouseInDrag
    let endIndex
    for(let i = 0;i < distanceArr.length;i++) {
      const {left,top,right,bottom} = distanceArr[i]
      if(left > (clientX - leftWidth) &&  i === 0) {
        endIndex = i
        break 
      }else if(left < (clientX - leftWidth) && i === distanceArr.length - 1) {
        endIndex = i
        break 
      }else if(left < (clientX - leftWidth) && distanceArr[i+1].left > (clientX - leftWidth) ) {
        // 判断向左还是向右
        // 向左运动,假设是2移动到1左边 这样0的左边< 1的左边> 实际就是第一个位置 需要 0+1 这样就是第一个位置
        if(i < index) {
          endIndex = i + 1
        }else {
          // 向右运动, 假设是在2移动到3右边,这样3的左边< 4的左边> 实际就是第三个位置 需要 3 这样就是第三个位置
          endIndex = i
        }
        break
      }
    }
    let newDragArr = [...dragArr]
    showLine(false)
    if(endIndex !== undefined) {
      if(index === endIndex) {
        mouseInDrag = {
          leftWidth: 0,
          rightWidth: 0,
          topWidth: 0,
          bottomWidth: 0
        }
        return 
      }else{
        newDragArr.splice(index,1)
        newDragArr.splice(endIndex,0,dragArr[index])
      }
    }
    setDragArr(newDragArr)
  }
  const handleDragOver = (e: any,index: number) => {
  }
  const handleDragEnter = (e: any,index: number) => {
  }
  
  const divMap = dragArr.map((item,index) => {
    return (
      <div 
        key={item.name}
        className={prefixCls+'-item'} 
        style={{background: item.backgroundColor}}
        draggable={true} 
        onDragStart={(e)=>handleDragStart(e,index)}
        onDragLeave={(e) => handleDragLeave(e,index)}
        onDragEnd={(e) => handleDragEnd(e,index)}
        onDragOver={(e) => handleDragOver(e,index)}
        onDragEnter={(e) => handleDragEnter(e,index)}
        onDrag = {(e) => draging(e,index)}
        // onClick = {(e) => handleClick(e,index)}
      >
        <div className="line" ></div>
        {item.name}
      </div>
    )
  })
  return (
    <div className={prefixCls} ref={dragArrRef}>     
      {divMap}
    </div>
  )
}

export default Drag
收获与不足
  • 这次拖拽实现学习到了react合成事件中e的作用,不需要自己原生处理
  • 函数节流的融汇贯通
  • 自定义hook的练习
  • 左右方向的逻辑判断

不足之处:

  • 这个拖拽只要页面初始加载时就判断出了距离屏幕的距离,当屏幕resize的时候并没有考虑(添加resize判断)
  • 只对横轴方向进行判断,如果两行就出bug(纵轴的处理与横轴基本类似,也需要逻辑判断)
  • 原生dom的展示ts报错,需要后续学习(对应上方的//@ts-ignore)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
React-dnd 拖拽排序是一种常见的前端交互方,可以通过以下代码实现:1. 首先需要安装 react-dnd 和 react-dnd-html5-backend 两个库:``` npm install --save react-dnd react-dnd-html5-backend ```2. 在组件中引入 DragDropContext、Droppable 和 Draggable 组件:``` import { DragDropContext, Droppable, Draggable } from 'react-dnd'; import { HTML5Backend } from 'react-dnd-html5-backend'; ```3. 定义一个数组作为拖拽列表的数据源:``` const items = [ { id: 1, name: 'Item 1' }, { id: 2, name: 'Item 2' }, { id: 3, name: 'Item 3' }, { id: 4, name: 'Item 4' }, { id: 5, name: 'Item 5' }, ]; ```4. 在组件中使用 DragDropContext 组件包裹整个列表,并在其中使用 Droppable 组件包裹每个拖拽项:``` <DragDropContext backend={HTML5Backend}> <Droppable droppableId="items"> {(provided) => ( <ul {...provided.droppableProps} ref={provided.innerRef}> {items.map((item, index) => ( <Draggable key={item.id} draggableId={item.id.toString()} index={index}> {(provided) => ( <li {...provided.draggableProps} {...provided.dragHandleProps} ref={provided.innerRef} > {item.name} </li> )} </Draggable> ))} {provided.placeholder} </ul> )} </Droppable> </DragDropContext> ```5. 在 Draggable 组件中使用 provided.draggableProps 和 provided.dragHandleProps 属性来实现拖拽功能,同时使用 provided.innerRef 属性来获取拖拽元素的引用。6. 在 Droppable 组件中使用 provided.droppableProps 和 provided.innerRef 属性来实现拖拽排序功能。7. 最后,需要在 DragDropContext 组件中定义 onDragEnd 回调函数来处理拖拽结束后的逻辑:``` function onDragEnd(result) { if (!result.destination) { return; } const newItems = Array.from(items); const [reorderedItem] = newItems.splice(result.source.index, 1); newItems.splice(result.destination.index, , reorderedItem); setItems(newItems); }<DragDropContext backend={HTML5Backend} onDragEnd={onDragEnd}> ... </DragDropContext> ```8. 在 onDragEnd 回调函数中,首先判断是否有目标位置,如果没有则直接返回。然后使用 Array.from 方法复制一份原始数据源,从中取出被拖拽的元素并删除,再将其插入到目标位置中,最后使用 setItems 函数更新数据源。以上就是 react-dnd 拖拽排序的代码实现

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值