Before l lifted a copy command, this time lifted a drag command.
What kind of snakeskin is it?
Since we are using Element-UI in our project, this directive only applies to the element-UI dialog component. If you are using other UI libraries that require this, it should also work.
In fact, the principle of drag is very simple:
- First mouse press (
onmousedown
)- Records the current value of the target element
left
andtop
值
- Records the current value of the target element
- Mouse movement (
onmousemove
)- Calculate the transverse distance of each movement (
disX
) and longitudinal distance (disY
) - And change the elements
left
(left = left + disX
) andtop
(top = top + disY
) value
- Calculate the transverse distance of each movement (
- Release the mouse (
onmouseup
)- Pull off a drag, do some finishing touches
The left and top values are easy to obtain. The key is disX and disY.
Let me generalize a bit:
-
ClientX: indicates the current X coordinate of the mouse
-
ClientY: indicates the current Y coordinate of the mouse
Then the pseudocode is:
-
DisX = clientX when mouse is down – clientX when mouse is released
-
DisY = clientY with mouse down – clientY with mouse off
That’s it. All right, let’s start coding.
// This helper method will be used next to get csS-related property values
const getAttr = (obj, key) = > (
obj.currentStyle
? obj.currentStyle[key]
: window.getComputedStyle(obj, false)[key]
);
const vDrag = {
inserted(el) {
/** * target: the container element of the dialog component ** header: the header of the dialog component */
const target = el.children[0];
const header = target.children[0];
// Mouse hand
header.style.cursor = 'move';
header.onmousedown = (e) = > {
// Record the coordinates of the mouse and the left and top values of the target element
const currentX = e.clientX;
const currentY = e.clientY
const left = parseInt(getAttr(target, 'left'));
const top = parseInt(getAttr(target, 'top'));
document.onmousemove = (event) = > {
// Calculate the distance of each mouse movement and change the positioning of the drag element
const disX = event.clientX - currentX;
const disY = event.clientY - currentY;
target.style.left = `${left + disX}px`;
target.style.top = `${top + disY}px`;
// Prevent the default behavior of the event, can solve the problem of dragging text when selected
return false; }// The drag ends when the mouse is released
document.onmouseup = (a)= > {
document.onmousemove = null;
document.onmouseup = null; }; }},// Every time the dialog is reopened, restore it
update(el) {
const target = el.children[0];
target.style.left = ' ';
target.style.top = ' ';
},
// Clear the event binding at last unmount
unbind(el) {
const header = el.children[0].children[0];
header.onmousedown = null; }};export default vDrap;
Copy the code
That’s the simplest drag and drop. Is that ok? Of course not. What’s the problem with that? If you push too hard and pull the whole thing out of the viewable area, you can’t pull it out.
So I have to perfect it, judge the boundary of the four directions, if you go beyond the boundary, you don’t move. The boundary value is actually the maximum distance that you can drag across the screen which is the maximum of disX and disY
- On the boundary:
target.offsetTop
offsetTop
: can represent the target element (target
) distance the top border from the top of the page
- Under the border:
body.height - target.offsetTop - header.height
header.height
: Reserved height: indicates that only the dragable area is left outside
- The left boundary:
target.offsetLeft + target.width - 50
- OffsetLeft: Indicates the distance between the left border of the target element and the left side of the page
50
: indicates the reserved width. You can specify the width as long as it is greater than0
Can, means to the left no matter how to drag will also stay50px
The width is on the outside
- The right boundary:
body.width - target.offsetLeft - 50
- here
50
Same as above, it means no matter how much you drag it to the left, it will remain. Right50px
The width is on the outside
- here
There are a number of different ways to compute the boundary, so you can try your own ideas. Then I sketched a diagram to help understand it, although it felt like only I could understand it. Haha…
ok
// ...
// The above code is omitted
header.onmousedown = (e) = > {
// ...
// The above code is omitted
// Calculate the boundary values of the four directions
const minLeft = target.offsetLeft + parseInt(getAttr(target, 'width')) - 50;
const maxLeft = parseInt(getAttr(document.body, 'width')) - target.offsetLeft - 50;
const minTop = target.offsetTop;
const maxTop = parseInt(getAttr(document.body, 'height'))
- target.offsetTop - parseInt(getAttr(header, 'height'));
document.onmousemove = (event) = > {
// Calculate the distance of each mouse movement and change the positioning of the drag element
const disX = event.clientX - currentX;
const disY = event.clientY - currentY;
// Determine the left and right boundaries
if (disX < 0 && disX <= -minLeft) {
target.style.left = `${left - minLeft)}px`;
} else if (disX > 0 && disX >= maxLeft) {
target.style.left = `${left + maxLeft}px`;
} else {
target.style.left = `${left + disX}px`;
}
// Determine the upper and lower boundaries
if (disY < 0 && disY <= -minTop) {
target.style.top = `${top - minTop)}px`;
} else if (disY > 0 && disY >= maxTop) {
target.style.top = `${top + maxTop}px`;
} else {
target.style.top = `${top + disY}px`;
}
return false;
};
}
Copy the code
After registering, it can be used:
<el-dialog v-drag title="Dialog box" :visible.sync="dialogVisible"></el-dialog>
Copy the code
I will not cover the hook function of the directive and how to register it globally. If you are interested, you can read my last article.