前端功能拖拽篇:dragleave拖拽事件穿透子元素的优雅解决方案

前情提要

在这里插入图片描述
在前端工作过程中,避免不了要接触各种技术,拖拽就是其中一个,大部分关于拖拽的基础知识和Demo都在MDN中写的很详细的,这里便不再赘述,给大家分享一个MDN飞机票


应用场景

每个人会接触不同的场景和需求,但是底层都是基于这些事件及API的,那我就直接分享几个有价值的点,可以节省大家的时间。

⭐拖拽改变元素位置

这个功能要依据几个事件
1、dragstart
2、dragover //dragover必须要在此事件中取消浏览器的默认行为,否则drop事件不会生效
3、drop

// 第一步,记录鼠标指针在元素上的偏移量
const rightItemDragStart = (event: any) => {
  // 记录初始鼠标偏移量
  mouseOffsetMap.value = { x: event.offsetX, y: event.offsetY }
  // 传递拖拽元素id
  event.dataTransfer.setData('text/plain', event.target.id)
  event.dataTransfer.setData('rightDrag', true)
}
// 第二步 设置阻止默认行为
const handleDragOver = (event: DragEvent) => {
  // 阻止默认行为以允许放置
  event.preventDefault()
}
// 第三步 计算元素位置赋值
const handleDrop = (event: any) => {
	// eventPos 这个位置就是元素放置后的准确位置
    eventPos = {
      x: event.offsetX - mouseOffsetMap.value.x,
      y: event.offsetY - mouseOffsetMap.value.y,
    }
    ...
    
  // 阻止默认行为(会作为某些元素的链接打开)
  event.preventDefault()
}

⭐拖拽改变目标区域的样式

依据俩个事件,要绑定给目标Dom
1、dragenter
2、dragleave

/**
 * 处理拖拽进入事件
 *
 * @param event 拖拽事件对象
 */
const handleDragEnter = (event: any) => {
  rightWrapRef.value?.classList.add('out-line')
}
/**
 * 当拖拽元素离开目标区域时触发
 *
 * @param event 拖拽事件对象
 */
const handleDragLeave = (event: DragEvent) => {
  rightWrapRef.value?.classList.remove('out-line')
}

⭐dragleave拖拽事件穿透子元素的优雅解决方案

如果目标区域的dom结构比较复杂,比如我在工作中的场景这样:
在这里插入图片描述
我想从右测往左侧的列表里拖拽,并且在进入左侧区域的时候,为区域增加一个虚线框,鼠标离开的时候取消虚线框。但此时问题出现了,在我拖拽进入区域后,每一个子元素的区域都会致使我重复触发enter,leave,导致虚线框闪烁,在一番调研后发现确实有这个问题,它不是事件的冒泡,也不是默认行为,而是改方法的特性导致的,所以大家只好另辟蹊径,怎么做的都有,但我认为最优雅的是下面这种。主要利用俩个方法
1、handleLeftDragEnter
2、handleLeftDragLeave

const draggingCounter = ref(0)
const handleLeftDragEnter = (event: any) => {
   draggingCounter.value++
  // 左侧元素放入左侧区域不处理
  leftWrapRef.value?.classList.add('out-line')
}
const handleLeftDragLeave = (event: any) => {
  draggingCounter.value--
  if(draggingCounter.value === 0) {
     leftWrapRef.value?.classList.remove('out-line')
  }
}

这里利用一个计数变量,大家看我打印这个一次拖拽的逻辑就很好理解了
在这里插入图片描述
俩次进入元素是因为进入最外部区域算一次,途径子元素算一次,离开子元素也是同理,我们通过判断数值为0来推导离开父元素的区域也是很合理的做法。大家如果还有什么好的建议和观点欢迎讨论学习。

最后

📚 vue专栏
☃️ 个人简介:一个喜爱技术的人。
🌞 励志格言: 脚踏实地,虚心学习。
❗如果文章还可以,记得用你可爱的小手点赞👍关注✅,我会在第一时间回、回访,欢迎进一步交流。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Min;

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值