Min

Min

持续投身前端开发领域,一起分享,交流,成长

Front-end Function Drag and Drop: Elegant Solution to Dragleave Event Penetrating Sub-elements

@[TOC](Table of Contents)

Introduction#

Insert Image Description Here
In the process of front-end work, it is inevitable to encounter various technologies, and drag and drop is one of them. Most of the basic knowledge and demos about drag and drop are written in detail in MDN, so I won't go into details here. I would like to share a MDN flight ticket with you.


Application Scenarios#

Everyone will encounter different scenarios and requirements, but they are all based on these events and APIs, so I will directly share a few valuable points that can save you time.

⭐ Drag and Drop to Change Element Position#

This feature relies on several events:

  1. dragstart
  2. dragover // The dragover event must cancel the default behavior of the browser in this event, otherwise the drop event will not take effect
  3. drop
// Step 1: Record the offset of the mouse pointer on the element
const rightItemDragStart = (event: any) => {
  // Record the initial mouse offset
  mouseOffsetMap.value = { x: event.offsetX, y: event.offsetY }
  // Pass the ID of the dragged element
  event.dataTransfer.setData('text/plain', event.target.id)
  event.dataTransfer.setData('rightDrag', true)
}
// Step 2: Prevent default behavior
const handleDragOver = (event: DragEvent) => {
  // Prevent default behavior to allow dropping
  event.preventDefault()
}
// Step 3: Calculate and assign the element position
const handleDrop = (event: any) => {
	// eventPos is the accurate position of the element after it is dropped
    eventPos = {
      x: event.offsetX - mouseOffsetMap.value.x,
      y: event.offsetY - mouseOffsetMap.value.y,
    }
    ...
    
  // Prevent default behavior (opens as a link for certain elements)
  event.preventDefault()
}

⭐ Drag and Drop to Change the Style of the Target Area#

This requires binding two events to the target DOM:

  1. dragenter
  2. dragleave
/**
 * Handle the dragenter event
 *
 * @param event The drag event object
 */
const handleDragEnter = (event: any) => {
  rightWrapRef.value?.classList.add('out-line')
}
/**
 * Triggered when the dragged element leaves the target area
 *
 * @param event The drag event object
 */
const handleDragLeave = (event: DragEvent) => {
  rightWrapRef.value?.classList.remove('out-line')
}

⭐ Elegant Solution for Dragleave Event Penetrating Child Elements#

If the DOM structure of the target area is complex, such as in the scenario I encountered at work:
Insert Image Description Here
I want to drag from the right side to the list on the left side, and when entering the left area, add a dashed border to the area, and remove it when the mouse leaves. However, a problem arises at this time. After I drag into the area, each child element's area will cause me to trigger enter and leave repeatedly, causing the dashed border to flicker. After some research, I found that this is indeed a problem, it is not event bubbling or default behavior, but the characteristics of this method. So everyone has to find another way. There are many ways to do it, but I think the most elegant one is the following. It mainly uses two methods:

  1. handleLeftDragEnter
  2. handleLeftDragLeave
const draggingCounter = ref(0)
const handleLeftDragEnter = (event: any) => {
   draggingCounter.value++
  // Do not process if the left element is placed in the left area
  leftWrapRef.value?.classList.add('out-line')
}
const handleLeftDragLeave = (event: any) => {
  draggingCounter.value--
  if(draggingCounter.value === 0) {
     leftWrapRef.value?.classList.remove('out-line')
  }
}

Here, we use a counter variable. You can understand the logic of dragging once by looking at the printout:
Insert Image Description Here
Entering the element twice is because entering the outermost area counts as one, and passing through each child element also counts as one. Leaving the child element is the same. It is reasonable to judge that leaving the parent element's area when the value is 0. If you have any suggestions or opinions, please feel free to discuss and learn.

Conclusion#

📚 Vue Column
☃️ Personal Profile: A person who loves technology.
🌞 Inspirational motto: Be down-to-earth and learn with an open mind.
❗ If the article is helpful, remember to like👍 and follow✅ with your lovely hands. I will reply and return the favor as soon as possible. Welcome to further discussion.

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.