22.5 Drag and Drop [JavaScript Advanced Programming 3rd Edition]

Drag and drop is a very popular user interface pattern. Its concept is simple: click on an object, hold down the mouse button, move the mouse to another area, and release the mouse button to "drop" the object there. Drag-and-drop functionality has also spread to the Web as an alternative to some of the more traditional configuration interfaces.
The basic concept of drag and drop is simple: create an absolutely positioned element so that it can be moved with the mouse. This technique is derived from a classic web technique called "mouse tailing". Mouse trailing is the movement of one or more images on the page following the mouse pointer. The basic code for single-element mouse trailing requires setting up an onmousemove event handler for the document, which always moves the specified element to the position of the mouse pointer, as shown in the following example.

EventUtil.addHandler(document, "mousemove",
function(event) {
	var myDiv = document.getElementById("myDiv");
	myDiv.style.left = event.clientX + "px";
	myDiv.style.top = event.clientY + "px";
});

Running it
In this example, the element's left and top coordinates are set to the event object's clientX and clientY properties, which places the element at the position of the pointer in the viewport. Its effect is that an element always follows the movement of the pointer on the page. As long as the function is implemented at the right moment (when the mouse button is pressed), and removed later (when the mouse button is released), drag and drop can be implemented. The simplest drag-and-drop interface can be implemented with the following code:

var DragDrop = function() {
var dragging = null;
function handleEvent(event) {
	// get event and target
	event = EventUtil.getEvent(event);
	var target = EventUtil.getTarget(event);
	// Determine the event type
	switch (event.type) {
	case "mousedown":
		if (target.className.indexOf("draggable") > -1) {
			dragging = target;
		}
		break;
	case "mousemove":
		if (dragging !== null) {
			//specify the location
			dragging.style.left = event.clientX + "px";
			dragging.style.top = event.clientY + "px";
		}
		break;
	case "mouseup":
		dragging = null;
		break;
	}
};
// public interface
return {
	enable: function() {
		EventUtil.addHandler(document, "mousedown", handleEvent);
		EventUtil.addHandler(document, "mousemove", handleEvent);
		EventUtil.addHandler(document, "mouseup", handleEvent);
	},
	disable: function() {
		EventUtil.removeHandler(document, "mousedown", handleEvent);
		EventUtil.removeHandler(document, "mousemove", handleEvent);
		EventUtil.removeHandler(document, "mouseup", handleEvent);
	}
}
} ();

run it

The DragDrop object encapsulates all the basic functionality of drag and drop. This is a singleton object and uses the module pattern to hide some implementation details. The dragging variable is initially null and will hold the element being dragged, so when the variable is not null, you know that something is being dragged. The handleEvent() function handles all three mouse events in the drag and drop function. It first gets a reference to the event object and the event target. After that, use a switch statement to determine which event style to fire. When the mousedown event occurs, it will check whether the class of the target contains the "draggable" class, and if so, store the target in dragging. This trick makes it easy to identify draggable elements through markup language rather than JavaScript scripting. The mousemove case for handleEvent() is the same as the previous code, but it checks to see if dragging is null. When it's not null, you know that dragging is the element to be dragged, and this will put it in the proper position. The mouseup case just resets dragging to null, invalidating the judgment in the mousemove event.

DragDrop also has two public methods: enable() and disable(), which simply add and remove all event handlers accordingly. These two functions provide additional control over the drag-and-drop functionality. To use the DragDrop object, just include this code on the page and call enable(). Drag and drop is automatically enabled for all elements containing the "draggable" class, as shown in the following example:

<div class="draggable" style="position:absolute; background:red"> </div>

Note that in order for an element to be dragged and dropped, it must be absolutely positioned.

22.5.1 Repair drag function

When you try the above example, you will find that the upper left corner of the element is always with the pointer. This result is a little annoying to the user, because the element seems to jump abruptly when the mouse starts to move. Ideally, the action should appear as if the element was "picked up" by the pointer, that is, when dragging the element, the point where the user clicks is where the pointer should remain (see Figure 22-4). .


 
To achieve the desired effect, some additional calculations must be done. You need to calculate the difference between the top left corner of the element and the pointer position. This difference should be determined when the mousedown event occurs, and will remain there until the mouseup event occurs.
By comparing the clientX and clientY properties of the event with the offsetLeft and offsetTop properties of the element, you can calculate how much space is needed in the direction and vertical direction when the pointer is dragged here after the first click of the horizontal user . See Figure 22-5.


 
 
In order to hold the difference in the x and y coordinates, a few more variables are needed. The variables diffX and diffY need to be used in the onmousemove event handler to properly position the element, as shown in the following example.

var DragDrop = function() {
	var dragging = null;
	diffX = 0;
	diffY = 0;
	function handleEvent(event) {
		// get event and target
		event = EventUtil.getEvent(event);
		var target = EventUtil.getTarget(event);
		// Determine the event type
		switch (event.type) {
		case "mousedown":
			if (target.className.indexOf("draggable") > -1) {
				dragging = target;
				diffX = event.clientX - target.offsetLeft;
				diffY = event.clientY - target.offsetTop;
			}
			break;
		case "mousemove":
			if (dragging !== null) {
				//specify the location
				dragging.style.left = (event.clientX - diffX) + "px";
				dragging.style.top = (event.clientY - diffY) + "px";
			}
			break;
		case "mouseup":
			dragging = null;
			break;
		}
	};
	// public interface
	return {
		enable: function() {
			EventUtil.addHandler(document, "mousedown", handleEvent);
			EventUtil.addHandler(document, "mousemove", handleEvent);
			EventUtil.addHandler(document, "mouseup", handleEvent);
		},
		disable: function() {
			EventUtil.removeHandler(document, "mousedown", handleEvent);
			EventUtil.removeHandler(document, "mousemove", handleEvent);
			EventUtil.removeHandler(document, "mouseup", handleEvent);
		}
	}
} ();

Run it
diffX and diffY variables are private, because only the handleEvent() function needs to use them. When the mousedown event occurs, the values ​​of these two variables can be calculated by subtracting the offsetLeft of the target from clientX and subtracting the offsetTop of the target from clientY. When the mousemove event is fired, these variables can be used to subtract from the pointer coordinates to get the final coordinates. The end result is a smoother dragging experience that is more in line with what the user expects.

22.5.2 Adding custom events

The drag-and-drop functionality isn't really usable yet, unless it's known when a drag has started. From this point of view, the preceding code does not provide any way to indicate that the dragging has started, is being dragged, or has ended. At this point, you can use custom events to indicate the occurrence of these events, allowing other parts of the application to interact with the dragging functionality.
Since the DragDrop object is a singleton that uses the module pattern, some changes are required to use the EventTarget type. First, create a new EventTarget object, then add enable() and disable() methods, and finally return this object. See below.

var DragDrop = function() {
	var dragdrop = new EventTarget(),
	dragging = null,
	diffX = 0,
	diffY = 0;
	function handleEvent(event) {
		// get events and objects
		event = EventUtil.getEvent(event);
		var target = EventUtil.getTarget(event);
		// Determine the event type
		switch (event.type) {
		case "mousedown":
			if (target.className.indexOf("draggable") > -1) {
				dragging = target;
				diffX = event.clientX - target.offsetLeft;
				diffY = event.clientY - target.offsetTop;
				dragdrop.fire({
					type: "dragstart",
					target: dragging,
					x: event.clientX,
					y: event.clientY
				});
			}
			break;
		case "mousemove":
			if (dragging !== null) {
				//specify the location
				dragging.style.left = (event.clientX - diffX) + "px";
				dragging.style.top = (event.clientY - diffY) + "px";
				//Trigger custom event
				dragdrop.fire({
					type: "drag",
					target: dragging,
					x: event.clientX,
					y: event.clientY
				});
			}
			break;
		case "mouseup":
			dragdrop.fire({
				type:
				"dragend",
				target: dragging,
				x: event.clientX,
				y: event.clientY
			});
			dragging = null;
			break;
		}
	};
	// public interface
	dragdrop.enable = function() {
		EventUtil.addHandler(document, "mousedown", handleEvent);
		EventUtil.addHandler(document, "mousemove", handleEvent);
		EventUtil.addHandler(document, "mouseup", handleEvent);
	};
	dragdrop.disable = function() {
		EventUtil.removeHandler(document, "mousedown", handleEvent);
		EventUtil.removeHandler(document, "mousemove", handleEvent);
		EventUtil.removeHandler(document, "mouseup", handleEvent);
	};
	return dragdrop;
} ();

This code defines three events: dragstart, drag, and dragend. They both set the dragged element as target, and give x and y properties to indicate the current position. They are triggered on the dragdrop object, which then adds enable() and disable() methods to the object before returning it. These minor changes in the module pattern enable DragDrop objects to support events, as follows:

DragDrop.addHandler("dragstart",
function(event) {
	var status = document.getElementById("status");
	status.innerHTML = "Started dragging " + event.target.id;
});
DragDrop.addHandler("drag",
function(event) {
	var status = document.getElementById("status");
	status.innerHTML += "<br/> Dragged " + event.target.id + " to (" + event.x + "," + event.y + ")";
});
DragDrop.addHandler("dragend",
function(event) {
	var status = document.getElementById("status");
	status.innerHTML += "<br/> Dropped " + event.target.id + " at (" + event.x + "," + event.y + ")";
});

Run it
Here, event handlers are added for each event of the DragDrop object. An element is also used to implement the current state and position of the dragged element. Once the element is dropped, you can see all the intermediate steps it has taken since it was first dragged.
Adding custom events to DragDrop can make this object more robust, and it will handle complex drag and drop functionality in web applications.

wrote

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326790718&siteId=291194637