There are many reasons to add drag-and-drop functionality to your pages, the simplest of which is to reorganize data. For example, you might want the user to be able to reorganize a series of page elements. Placing an input or select component next to each element to represent their order is one solution. Making the group of elements drag-and-drop is one. Alternatives. Or maybe you want to have a navigation window on your website that can be moved by the user. These are all simple reasons to use drag and drop because you can!
It’s not very complicated to implement drag-and-drop effects on your web pages. First, we know the position of the mouse, then we need to know when the user clicked on an element so that we know to be ready to start dragging it, and finally we need to move the element.
Capture the movement of the mouse
In the first step, we need to get the coordinates of the mouse. This function can be achieved by passing a function and assigning it to document.onmousemove:
Code
document.onmousemove = mouseMove;
function mouseMove(ev) {
ev = ev || window.event;
var mousePos = mouseCoords(ev);
}
function mouseCoords(ev) {
if(ev.pageX || ev.pageY) {
return {x:ev.pageX, y:ev.pageY};
}
return {
x:ev.clientX document.body.scrollLeft - document.body.clientLeft,
y:ev.clientY document.body.scrollTop - document.body.clientTop
};
}
First we need to explain the event object. Whenever you move, click the mouse, press a key, etc., an event occurs. In IE, this event is global and is stored in window.event. For Firefox and other browsers, this event will be passed to any function that points to this page action. Therefore, we make document.onmousemove point to the mouse movement function, and the mouse movement function gets the event object.
In the above code, ev contains event objects in all browser environments. In Firefox, "||window.event" will be ignored because it already contains the event. In IE, the value of ev is empty, so its value needs to be set to window.event.
In this article we need to capture the coordinates of the mouse multiple times, so we wrote a mouseCoords method, which has one parameter: event.
We are going to discuss the differences between IE and other browsers again. Firefox and other browsers use event.pageX and event.pageY to represent the mouse position relative to the document. If you have a 500*500 window and the mouse is in the middle of the window, the values of pageX and pageY will both be 250. If you scroll the window down 500 pixels, the value of pageY is 750.
In contrast, Microsoft's IE uses event.clientX and event.clientY to represent the position of the mouse relative to the window, not the current document. In the same example, if you place the mouse in the middle of a 500x500 window, the clientX and clientY values will both be 250. If you scroll down the page, clientY will still be 250 because it is measured relative to the window, not the current document. Therefore, in the mouse position, we should introduce the scrollLeft and scrollTop attributes of the document document body area. Finally, the document in IE is not actually at the position (0,0). There is a small (usually 2px) border around it. document.body.clientLeft and document.body.clientTop contain the width of this border, thus also They need to be introduced in the mouse position.
Fortunately, now that we have the mouseCoords function, we no longer have to worry about getting the mouse position.
Capture mouse clicks
Next, we have to know when the mouse is clicked and when it is released. If we skip this step, whenever your mouse moves over these elements, it will have the effect of dragging these elements, which is annoying and counterintuitive.
Here, there are two functions to help us: onmousedown and onmouseup. Previously we pointed document.onmousemove to a function, so it seems logical that both document.onmousedown and document.onmouseup should point to functions. If we let document.onmousedown point to a function, then this function will be executed when the mouse clicks on any element: text, image, table, etc. We only want specific elements on the page to have the ability to be dragged and dropped. Therefore, we can achieve this through the following method:
Code
document.onmouseup = mouseUp;
var dragObject = null;
function makeClickable(object) {
object.onmousedown = function () {
dragObject = this;
}
}
function mouseUp(ev) {
dragObject = null;
}
We now have a variable dragObject that contains whatever element you clicked on. When you release the mouse, the dragObject is set to empty, so when the dragObject is not empty, we need to perform a drag operation.
Moving Elements
We now know how to capture mouse movements and clicks. The next thing we need to do is move any element we want to drag. First, to move an element to exactly where we want it to be on the page, the position value of the element's style sheet must be absolute, which means you can set its style.top or style.left, with the measurement relative to the top left of the page. corner, because all our mouse movements are relative to the upper left corner of the page, which is usually the case.
Once we set item.style.position='absolute', we need to change the top and left positions of the element to make it move!
Code
document.onmousemove = mouseMove ;
document.onmouseup = mouseUp;
var dragObject = null ;
var mouseOffset = null ;
function getMouseOffset(target, ev) {
ev = ev || window.event;
var docPos = getPosition(target);
var mousePos = mouseCoords(ev);
return {x:mousePos.x - docPos.x, y:mousePos.y - docPos.y};
}
function getPosition(e) {
var left = 0;
var top = 0;
while (e.offsetParent) {
left = e.offsetLeft;
top = e.offsetTop;
e = e.offsetParent;
}
left = e.offsetLeft;
top = e.offsetTop;
return {x:left, y:top};
}
function mouseMove(ev) {
ev = ev || window.event;
var mousePos = mouseCoords(ev);
if (dragObject) {
dragObject.style. position = 'absolute';
dragObject.style.top = mousePos.y - mouseOffset.y;
dragObject.style.left = mousePos.x - mouseOffset.x;
return false ;
}
}
function mouseUp() {
dragObject = null ;
}
function makeDraggable(item) {
if (!item) return ;
item.onmousedown = function (ev) {
dragObject = this ;
mouseOffset = getMouseOffset(this, ev);
return false ;
}
}
You will notice that these codes are based on our previous example (refer to the previous article). Put them together and you will be able to move elements at will.
When we click on an element, another variable, mouseOffset, is stored. mouseOffset simply contains the position information of the element we clicked. If we have a 20*20px image and click in the middle of the image, the mouseOffset should be {x:10, y:10}. If we click on the top left corner of the image, mouseOffset should be {x:0, y:0}. We use it in the position information after the mouse is moved. If we don't store this value, the element's position relative to the mouse will be the same no matter where you click on the element.
The mouseOffset function uses another function getPosition. The purpose of getPosition is to return the coordinate position of the element relative to the documemt document. If we simply read item.offsetLeft or item.style.left, what we get will be the position of the element relative to its parent element, not the document document. In our script, all elements are relative to the document, so this is required.
To complete the work of getting the position of the element relative to the document, getPosition starts from its own parent, loops to get its left and top values and accumulates them, so that we get the distance between the element and the top of the document that we want. Cumulative value on the left.
When we get this information and move the mouse, mouseMove starts running. First, we need to ensure that the item.style.position value is absolute. Then, when we move the element to any place, the mouse position will be subtracted from the offset of the mouse relative to the element that we recorded previously. When the mouse is released, dragObject will be set to null and the mouseMove function will no longer do anything.
Placing Elements
Our previous example already dealt with this by simply dragging an element and dropping it. Then, there are usually other purposes when we drop the element, let's drag the element to the garbage bin as an example, or we may want to align the element with a specific area on the page.
Unfortunately we get into a relatively major problem here. Because the element we are moving is always directly under our mouse, it is impossible to cause mouseover, mousedown, mouseup or mouse operations on other elements on the page. If you move an element to the garbage bin, your mouse will always be over the moved element, not the garbage bin.
So how do we deal with this problem? There are several solutions here. The purpose of the mouseOffset mentioned earlier is to ensure that the element is always in the correct position under the mouse. If you ignore this and always make the element to the bottom right of the mouse, your mouse will not be dragged by you. elements are hidden, we won't run into problems. But in fact, this is often not the case. For the sake of beauty, we usually want to keep the element below the mouse.
Another option is to not move the element you are dragging. You can change the mouse style to tell the user that you are dragging an element until you drop it somewhere. This solves our problem, but creates the same problem as the previous solution: aesthetics.
Our final solution affects neither the element you are moving nor the element at the end of the move (such as the garbage bin). Unfortunately, this is more difficult than the previous two solutions. What we are going to do is get a set of targets that we want to place, and when the mouse is released, we manually check the current mouse position relative to each target to see if the mouse is released at the position of one of the targets, and if so , we know we've placed the element on our target.
Code
/*
All code from the previous example is needed with the exception
of the mouseUp function which is replaced below
*/
var dropTargets = [];
function addDropTarget(dropTarget) {
dropTargets. push(dropTarget);
}
function mouseUp(ev) {
ev = ev || window.event;
var mousePos = mouseCoords(ev);
for (var i = 0 ; i < dropTargets.length; i ) {
var curTarget = dropTargets[i];
var targPos = getPosition(curTarget);
var targWidth = parseInt(curTarget.offsetWidth);
var targHeight = parseInt(curTarget.offsetHeight);
if (
(mousePos.x > targPos.x) &&
(mousePos. < (targPos.x targWidth)) &&
(mousePos. y > targPos.y) &&
(mousePos.y < (targPos.y targHeight))) {
// dragObject was dropped onto curTarget!
}
}
dragObject = null ;
}
In this example, when the mouse is released, we loop through each target where the element may be placed. If the mouse pointer is on the target, we have an event to place the element. The mouse abscissa is greater than the left abscissa of the target element ( mousePos.x>targPos.x), is smaller than the abscissa coordinate on the right side of the target element (mousePos.x<(targPos.x targWidth)). We make the same judgment for the Y coordinate. If all of these values return true, then our mouse is within the range of the target element.
Integrate all functions
Finally we use all code snippets to create a complete drag-and-drop function script. The first thing we have to do is DOM manipulation. If you are not very familiar with this, you can read "JavaScript Primer on DOM Manipulation".
The following code creates containers and container groups so that each element can be dragged in these containers. This is done based on the second demo of this article. This code can be used to rearrange the order of elements, move the navigation window to the left or right side of the page, or add any other functionality you can think of.
We will use pseudo code to explain step by step, leaving the real code for readers to view through comments.
1. When the document is loaded for the first time, we create a DIV tag named dragHelper. When we start moving an element, the dragHelper will become a hidden element and can be moved around. The actual element is not dragged, only moved using insertBefore and appendChild. We hide the dragHelper at the beginning.
2. We create mouseDown and mouseUp functions. Initially, all of these functions assume that the state of the mouse button is recorded, so that the iMouseDown variable is true when the mouse is pressed and false when it is not pressed.
3. We create a global variable DragDrops and a function CreateDragContainer. DragDrops contain a set of related containers. Any variables (representing containers) passed into CreateDragContainer are organized into a new collection, allowing elements to move freely between these containers. Through setAttribute, the CreateDragContainer function also binds the elements in each container together.
4. Now that our code knows the collection where each element is located, let’s look at the mouseMove function. The mouseMove function first sets a variable target, which represents the target element under the mouse. If this element is in the collection (judged by getAttribute), continue the following operations:
4.1. First, when necessary, we run a simple script To change the class attribute of the target element, this creates a flipping effect.
4.2. Then we check whether the mouse is clicked (because our code has already run here), if the event occurs:
4.2.1. Set the variable curTarget to the current element.
4.2.2. Record the current position of the element in the document so that its value can be retrieved when needed.
4.2.3. Clone the current element to dragHelper, allowing us to move the hidden backup of the element.
4.2.4. Because we have a complete backup of the dragged element in dragHelper, this element will always be under the mouse, we must remove the dragObj attribute to let the code know that dragObj is no longer in the collection.
4.2.5. We quickly record the current position, width and height of each element in the collection. We only have to do this once when the element first starts being dragged, otherwise we have to do it every time the mouse moves, or even hundreds of times a second.
4.3. If the mouse is not clicked, either we have the same target element as before, or there is no target element. In either case, we will not do anything.
5. Now we check the curTarget variable. curTarget should only contain a dragged object, so if it exists, it means we are dragging an element:
5.1. Move the hidden DIV to the mouse. This element can be dragged like the element created earlier in the article.
5.2. Then we check whether the mouse exists in each container in the current collection.
5.2.1. If the mouse is in a container, we check each element in the container to see where the element we are dragging belongs to.
5.2.2. Then we place the dragged element in front of another element in the container, or at the last position of the container.
5.2.3. Finally we make sure the element is visible.
6. All that remains is to capture the mouseUp event:
6.1. First you need to hide the dragHelper: it is no longer needed since we are not dragging anything.
6.2. If the dragged element is visible, it already exists in whatever container it belongs to, and all work is done.
6.3. If the dragged element is not visible, we put it back to its original location.