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

@TOC

前情提要

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

应用场景

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

⭐拖拽改变元素位置

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

Copy
// 第一步，记录鼠标指针在元素上的偏移量
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

Copy
/**
* 处理拖拽进入事件
*
* @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

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