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