拖拽的整体主要代码 ——拖拽完整代码
拖拽的整体主要代码
实现本次拖拽的效果的主要代码如下
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)