The specific requirements

Implement a draggable content component based on Vue 2.x

  • Press the left button of the mouse to start dragging, and move with the cursor. Release the left button and stop moving, that is, cannot drag

  • The content area is partially embedded with iframe

  • There are operation buttons in the upper right corner

Source code Overview

The drag effect is implemented using mousedown, Mousemove and Mouseup. The code is as follows:

<template>
  <div :class="contentClassObj" @mousedown.stop="handleMoveStart">
    <div :class="buttonArea">
      <button @click="handleAction">Action</button>
    </div>
    <div :class="headerClassObj"></div>
    <div :class="bodyClassObj">
      <iframe :src="iframeUrl"></iframe>
    </div>
    <div :class="footerClassObj"></div>
  </div>
</template>
Copy the code

The handleMoveStart is executed when the mouse is pressed

export default {
  // Data, computed
  methods: {
    handleMoveStart(e) {}, // Drag to start
    handleMove(e) {}, / / drag
    handleMoveUp(e) {}, // Drag to end
    handleAction() {}, // Button execution event (resulting in position change)
  },
  mounted() {
    // Listen for mouse movement & mouse release events
    window.addEventListener("mousemove".this.handleMove);
    window.addEventListener("mouseup".this.handleMoveUp);
  },
  beforeDestroy() {
    window.removeEventListener("mousemove".this.handleMove);
    window.removeEventListener("mouseup".this.handleMoveUp); }};Copy the code

The problem

Run the code, and during operation, occasionally find the following bugs

1. The component can be dragged and still move with the cursor after releasing the left mouse button — no mouseup event?

2, Click the button, instead of executing handleAction, execute handleMoveStart — click event does not execute?

why

Question 1

After repeated operations, the problem is repeated and combined with the code, we find that the mouseup event is missing because:

  • A) Trigger drag event to main page (Drag & Drop)

  • B) Trigger drag event to IFrame (content area is IFrame)

  • C) Move the cursor inside the IFrame and release the mouse

Refer to the link

Question 2

Reason: repeated tests, found that “click” : the left mouse button was released after two seconds

Before the cause is found, the repetition times are not many. Then carefully check the code and trigger the following three events according to the timing:

  • Mousedown: When the mouse is moved over the element and the key (left/right) is pressed

  • Mouseup: When releasing the button (left/right) on an element

  • Click: When the mouse hovers over an element and then presses and releases the left mouse button

Pressing and releasing the left mouse button on the same element triggers mousedown, mouseup, and click

Refer to the link

The mousedown event of the parent element will be triggered if the mouse cursor stays over the action button and the left button is held down for a long time. Because the stop modifier (@mouseDown.stop) was added to prevent the event from propagating further, the handleAction event is no longer triggered

The solution

Question 1

  • 1. For a), the component needs to listen to the dragstart event to prevent the main page from triggering the drag & drop operation:
mounted() {
    window.addEventListener("dragstart".(e) = > {
        e.preventDefault();
        e.stopPropagation(); 
    });
},
beforeDestroy() {
    / /...
}
Copy the code
  • 2. Similarly, for b) and C), we need to listen for the drag and mouse release events of the iframe page:

For this monitoring, iframe needs to communicate with the main page. For details, see The communication method between vUE page and Iframe Page

Using Window. postMessage: For cross-source communication, one window can get a reference to another window, one window distributes the message, and the other window receiving the message is free to process the event as needed. link

Iframe passes events to the page
document.addEventListener("dragstart".() = > {
    window.parent.postMessage({ type: "dragstart" }, "*");
});
document.addEventListener("mouseup".() = > {
    window.parent.postMessage({ type: "mouseup" }, "*");
});
Copy the code
The page accepts the information and processes it
mounted() {
    window.addEventListener('message'.(e) = > {
        let type = e.data.type;
        if (type == "dragstart") {
            // Prevent the drag & drop operation of iframe from triggering
            e.preventDefault();
            e.stopPropagation();   
        } else if (type == "mouseup") {
            // Move the mouse over the iframe area and release the left button to stop dragging
            this.handleMoveUp(); }}); },beforeDestroy() {
    / /...
}
Copy the code

Question 2

  • Solution: Child element events prevent bubbling up

To avoid executing the parent element’s mousedown events, add @mousedown.stop or e.topPropagation () to its mousedown event:

<button @click="handleAction" @mousedown.stop>Action</button>
Copy the code

Last but not least

If there is anything wrong, please give me your advice