This is the 4th day of my participation in the August More Text Challenge

Drag and drop event

Types of drag events

Drag means that the user holds down the mouse button on an object, drags it to another location, and then releases the mouse button to place the object there.

There are several types of objects to drag, including element nodes, images, links, selected text, and so on. In web pages, everything (images, links, selected text) can be dragged directly, except element nodes, which cannot be dragged by default. To make the element node dragable, set the draggable attribute of the node to true.

<div draggable="true">This area can be dragged</div>
Copy the code

The div block of the above code can be dragged directly in the web page with the mouse. When the mouse button is released, the drag effect disappears and the block remains in its original position.

The draggable attribute can be applied to any element node, but images () and links () can be dragged without this attribute. For them, this attribute is usually set to false to prevent dragging of both elements.

Note that once the draggable attribute of an element node is set to true, text or child nodes inside the node cannot be selected with the mouse.

Drag events are continuously triggered when an element node or selected text is dragged, including the following events.

  • drag: Fires continuously (hundreds of milliseconds apart) on the node being dragged.
  • dragstart: Emitted when the user starts dragging on the node being draggedtargetAttributes are nodes that are being dragged. Normally, the data to be dragged should be specified in the listener function for this event.
  • dragend: Triggered at the end of the drag (releasing the mouse key or pressing the ESC key) on the node being draggedtargetAttributes are nodes that are being dragged. It has to do withdragstartEvent, fired on the same node. Regardless of whether the drag crosses the window or is cancelled in the middle,dragendEvents are always triggered.
  • dragenter: Triggers an event on the current node when dragging into the current nodetargetProperty is the current node. Normally, the listener for this event should specify whether to allow the dropped data to be dropped on the current node. If the current node does not have a listener for the event, or if the listener does nothing, it means that data is not allowed to be dropped at the current node. The visual drag to the current node is also set in the listener function for this event.
  • dragover: Emitted continuously (hundreds of milliseconds apart) on the current node when dragged above the current nodetargetProperty is the current node. The event anddragenterThe difference between events is,dragenterEvents are emitted when entering the node, and as long as you don’t leave the node,dragoverEvents will continue to fire.
  • dragleave: Triggered on the current node when the drag operation leaves the current node rangetargetProperty is the current node. If you want to visually display the drag off operation current node, set it in the listener function for this event.
  • drop: Triggered on the target node when the dragged node or selected text is released to the target node. Note if the current node does not allowdropEven if the mouse key is released above the node, the event will not be triggered. This event is not triggered if the user cancels the operation by pressing the ESC key. The listener function for this event is responsible for pulling the drag data and processing it.

The following example shows how to dynamically change the background color of the dragged node.

div.addEventListener('dragstart'.function (e) {
  this.style.backgroundColor = 'red';
}, false);

div.addEventListener('dragend'.function (e) {
  this.style.backgroundColor = 'green';
}, false);
Copy the code

In the code above, when the div node is dragged, the background color changes to red, and when the drag is complete, it changes back to green.

Here is an example of how to drag a node from the current parent to another parent.


      
The node can be dragged
*/
// The dragged node var dragged; document.addEventListener('dragstart'.function (event) { // Save the dragged node dragged = event.target; // The background color of the dragged node becomes transparent event.target.style.opacity = 0.5; }, false); document.addEventListener('dragend'.function (event) { // The background color of the dragged node returns to normal event.target.style.opacity = ' '; }, false); document.addEventListener('dragover'.function (event) { // Prevents the drag effect from being reset, allowing the dragged node to be placed in the destination node event.preventDefault(); }, false); document.addEventListener('dragenter'.function (event) { // The background color of the destination node becomes purple // Since the event bubbles, the nodes are filtered if (event.target.className === 'dropzone') { event.target.style.background = 'purple'; }},false); document.addEventListener('dragleave'.function( event ) { // The background color of the target node is restored if (event.target.className === 'dropzone') { event.target.style.background = ' '; }},false); document.addEventListener('drop'.function( event ) { // Prevent event default behavior (such as opening links on some element nodes), event.preventDefault(); if (event.target.className === 'dropzone') { // Restore the background color of the target node event.target.style.background = ' '; // Insert the dragged node into the destination nodedragged.parentNode.removeChild(dragged); event.target.appendChild( dragged ); }},false); Copy the code

There are a few things to note about dragging events.

  • The drag process only triggers these drag events. The mouse event does not fire, even though the mouse is moving.
  • Dragging files from the operating system to the browser does not triggerdragstartanddragendEvents.
  • dragenteranddragoverA listener function for the event that retrieves dragged data (that is, allows dropped elements). Since large areas of the web page are not suitable as target nodes for dropping dropped elements, the default setting for both events is that the current node is not allowed to accept dropped elements. If you want to drop data on the target node, you must first prevent the default behavior of these two events.
<div ondragover="return false">
<div ondragover="event.preventDefault()">
Copy the code

In the code above, you cannot drop the dragged node on the DIV node without canceling the drag event or preventing the default behavior.

DragEvent interface

Drag events inherit from the DragEvent interface, which in turn inherits from the MouseEvent and Event interfaces.

The browser natively provides a DragEvent() constructor that generates an instance object of the DragEvent.

new DragEvent(type, options)
Copy the code

The DragEvent() constructor takes two arguments. The first argument is a string indicating the type of the event. The second parameter is an optional configuration object for the event, which sets the properties of the event. In addition to accepting MouseEvent and Event interface configuration properties, configuration objects can also set the dataTransfer property to be either NULL or an instance of the dataTransfer interface.

Instance objects of the DataTransfer are used to read and write data transferred during drag events, as described in the Section DataTransfer Interface below.

DataTransfer Interface overview

All instances of drag events have a DragEvent. DataTransfer property that reads and writes data that needs to be passed. The value of this property is an instance of the DataTransfer interface.

The browser natively provides a DataTransfer() constructor that generates DataTransfer instance objects.

var dataTrans = new DataTransfer();
Copy the code

The DataTransfer() constructor takes no arguments.

Dragged data is divided into two aspects: the type of data (also known as format) and the value of the data. The type of data is a MIME string (such as text/plain, image/ JPEG), and the value of the data is a string. In general, if you drag a piece of text, the data defaults to that text. If you drag a link, the data defaults to the URL of the link.

At the start of the drag event, the developer can provide data types and data values. During drag, the developer checks the data type through the listener functions for the dragenter and dragover events to determine whether the dropped object is allowed to be dropped. For example, in areas where only links are allowed to be dropped, check whether the data type being dropped is text/uri-list.

When a DROP event occurs, the listener retrieves the dropped data and processes it.

Instance properties of the DataTransfer

DataTransfer.dropEffect

The datatransfer. dropEffect property is used to set the effect of dropping a node that is being dragged, which affects the shape of the mouse as it is dragged over the associated area. It may take the following values.

  • Copy: Copies the dragged node
  • Move: Moves the dragged node
  • Link: Creates a link to the dragged node
  • None: Cannot drop the dragged node

Setting any values other than those above is invalid.

target.addEventListener('dragover'.function (e) {
  e.preventDefault();
  e.stopPropagation();
  e.dataTransfer.dropEffect = 'copy';
});
Copy the code

In the code above, once the element is dropped, the receiving region copies the node.

The dropEffect attribute is normally set in the listener function of the Dragenter and dragover events. It has no effect on the dragstart, drag, and dragleave events. Because this property is only valid for the region that receives the dragged node, it is not valid for the dragged node itself. After entering the target area, the drag action will be initialized to the desired effect.

DataTransfer.effectAllowed

DataTransfer. EffectAllowed is allowed in the attribute set the drag effect. It may take the following values.

  • Copy: Copies the dragged node
  • Move: Moves the dragged node
  • Link: Creates a link to the dragged node
  • CopyLink: allowscopyorlink
  • CopyMove: allowscopyormove
  • LinkMove: allowslinkormove
  • All: allows all effects
  • None: Cannot drop the dragged node
  • Uninitialized: The default value is the same as that of initializedall

If an effect is not allowed, the user cannot achieve that effect in the target node.

This property and the dropEffect property are two sides of the same coin. The former sets the effects allowed by the node being dragged, and the latter sets the effects of the region receiving the drag, and they are often used together.

A listener function for the dragstart event that can be used to set this property. Setting this property in other event listeners is invalid.

source.addEventListener('dragstart'.function (e) {
  e.dataTransfer.effectAllowed = 'move';
});

target.addEventListener('dragover'.function (e) {
  e.dataTransfer.dropEffect = 'move';
});
Copy the code

If either of the dropEffect and Effectalhoward properties is None, the drop operation cannot be performed on the target node.

DataTransfer.files

The datatransfer. files property is a FileList object that contains a list of local files that can be passed during drag-and-drop operations. If the drag does not involve files, the property is an empty FileList object.

Here is an example of receiving a drag file.

// The HTML code is as follows
// 
      
// Drag the file here // </div> var div = document.getElementById('output'); div.addEventListener("dragenter".function( event ) { div.textContent = ' '; event.stopPropagation(); event.preventDefault(); }, false); div.addEventListener("dragover".function( event ) { event.stopPropagation(); event.preventDefault(); }, false); div.addEventListener("drop".function( event ) { event.stopPropagation(); event.preventDefault(); var files = event.dataTransfer.files; for (var i = 0; i < files.length; i++) { div.textContent += files[i].name + ' ' + files[i].size + 'byte \ n'; }},false); Copy the code

In the above code, information about the file being dragged is read through the datatransfer. files property. If you want to read the contents of the file, you use the FileReader object.

div.addEventListener('drop'.function(e) {
  e.preventDefault();
  e.stopPropagation();

  var fileList = e.dataTransfer.files;
  if (fileList.length > 0) {
    var file = fileList[0];
    var reader = new FileReader();
    reader.onloadend = function(e) {
      if (e.target.readyState === FileReader.DONE) {
        var content = reader.result;
        div.innerHTML = 'File: ' + file.name + '\n\n'+ content; } } reader.readAsBinaryString(file); }});Copy the code

DataTransfer.types

The datatransfer. types attribute is a read-only array where each member is a string containing the dragged data format (usually MIME values). For example, if you drag text, the corresponding member is text/plain.

Here is an example of checking the type of the dataTransfer attribute to determine whether the drop operation is allowed on the current node.

function contains(list, value){
  for (var i = 0; i < list.length; ++i) {
    if(list[i] === value) return true;
  }
  return false;
}

function doDragOver(event) {
  var isLink = contains(event.dataTransfer.types, 'text/uri-list');
  if (isLink) event.preventDefault();
}
Copy the code

In the above code, dropping on the current node is only allowed if one of the nodes being dragged is a link.

DataTransfer.items

The datatransfer. items property returns an array-like read-only object (DataTransferItemList instance), each member of which is the object being dragged (DataTransferItem instance). If the drag does not contain an object, an empty object is returned.

The DataTransferItemList instance has the following properties and methods.

  • length: Returns the number of members
  • add(data, type): adds a specified content and type (e.gtext/htmlandtext/plain) as a member
  • add(file):addMethod to add a file as a member
  • remove(index): Removes the member at the specified position
  • clear(): Removes all members

The DataTransferItem instance has the following properties and methods.

  • kind: Returns the type of the member (stringorfile).
  • type: Returns the type of the member (usually a MIME value).
  • getAsFile(): Returns the file if dragged, otherwise returns the filenull.
  • getAsString(callback)If a string is dragged, the character is passed to the specified callback function for processing. This method is asynchronous, so you need to pass in a callback function.

Here’s an example.

div.addEventListener('drop'.function (e) {
  e.preventDefault();
  if(e.dataTransfer.items ! =null) {
    for (var i = 0; i < e.dataTransfer.items.length; i++) {
      console.log(e.dataTransfer.items[i].kind + ':'+ e.dataTransfer.items[i].type); }}});Copy the code

DataTransfer instance method

DataTransfer.setData()

The datatransfer.setData () method is used to set the data carried by the drag event. This method does not return a value.

event.dataTransfer.setData('text/plain'.'Text to drag');
Copy the code

The code above adds plain text data to the current drag event.

This method takes two arguments, both strings. The first argument represents the data type (such as text/plain), and the second argument is concrete data. If the specified type of data does not exist in the dataTransfer property, the data will be added, otherwise the original data will be replaced with new data.

If you drag the text box or the selected text, the corresponding text data is added to the dataTransfer property by default without manually specifying it.

<div draggable="true">
  aaa
</div>
Copy the code

In the code above, dragging the

element automatically carries the text data AAA.

Using the setData method, you can replace the original data.

<div
  draggable="true"
  ondragstart="event.dataTransfer.setData('text/plain', 'bbb')"
>
  aaa
</div>
Copy the code

In the code above, drag data is actually BBB, not AAA.

Here’s how to add the other types of data. Since text/plain is the most commonly supported format, it is recommended that you always end up saving a copy of the data in plain text for compatibility.

var dt = event.dataTransfer;

// Add a link
dt.setData('text/uri-list'.'http://www.example.com');
dt.setData('text/plain'.'http://www.example.com');

// Add HTML code
dt.setData('text/html'.'Hello there, <strong>stranger</strong>');
dt.setData('text/plain'.'Hello there, <strong>stranger</strong>');

// Add the URL of the image
dt.setData('text/uri-list', imageurl);
dt.setData('text/plain', imageurl);
Copy the code

You can provide data in multiple formats at once.

var dt = event.dataTransfer;
dt.setData('application/x-bookmark', bookmarkString);
dt.setData('text/uri-list'.'http://www.example.com');
dt.setData('text/plain'.'http://www.example.com');
Copy the code

In the above code, drop events can drop different values on different objects by placing three types of data on the same event. Note that the first format is a custom format that cannot be read by the browser by default, meaning that only a node with a particular code deployed can drop this data.

DataTransfer.getData()

The datatransfer.getData () method takes a string (representing the data type) as an argument and returns the data of the specified type carried by the event (usually added using the setData method). Returns an empty string if the specified type of data does not exist. Data can be retrieved only after the DROP event is triggered.

The following is a listener for the drop event that fetches the specified type of data.

function onDrop(event) {
  var data = event.dataTransfer.getData('text/plain');
  event.target.textContent = data;
  event.preventDefault();
}
Copy the code

The code above takes the text data of the drag event and replaces it with the text content of the current node. Note that you must also undo the browser’s default behavior, because if the user drags a link, the browser opens it in the current window by default.

The getData method returns a string that must be parsed manually if it contains more than one piece of data.

function doDrop(event) {
  var lines = event.dataTransfer.getData('text/uri-list').split('\n');
  for (let line of lines) {
    let link = document.createElement('a');
    link.href = line;
    link.textContent = line;
    event.target.appendChild(link);
  }
  event.preventDefault();
}
Copy the code

In the code above, the getData method returns a set of links that must be parsed by itself.

The type value is specified as URL, and the first valid link can be retrieved.

var link = event.dataTransfer.getData('URL');
Copy the code

The following example fetches data from multiple types of data.

function doDrop(event) {
  var types = event.dataTransfer.types;
  var supportedTypes = ['text/uri-list'.'text/plain'];
  types = supportedTypes.filter(function (value) { types.includes(value) });
  if (types.length) {
    var data = event.dataTransfer.getData(types[0]);
  }
  event.preventDefault();
}
Copy the code

DataTransfer.clearData()

The datatransfer.clearData () method takes a string (representing the data type) as an argument to remove the data of the specified type carried by the event. If no type is specified, all data is deleted. If the specified type does not exist, calling this method has no effect.

event.dataTransfer.clearData('text/uri-list');
Copy the code

The above code clears the text/ URI-list data carried by the event.

This method does not remove Files that are dragged, so the datatransfer.types attribute may still return Files types after calling this method (if file drags exist).

Note that this method can only be used within the listener function of the dragstart event, because this is the only time the data for the drag operation is writable.

DataTransfer.setDragImage()

During the drag process (after the dragstart event is triggered), the browser displays a picture that moves with the mouse, representing the dragged node. This image is created automatically and usually shows the appearance of the node being dragged, so you don’t need to set it up yourself.

DataTransfer. SetDragImage () method can customize the picture. It takes three arguments. The first is the node or the

node. If omitted or null, the appearance of the dragged node is used. The second and third parameters are the abscissa and ordinate of the mouse relative to the upper left corner of the image.

Here’s an example.


      
drag me
*/
var div = document.getElementById('drag-with-image'); div.addEventListener('dragstart'.function (e) { var img = document.createElement('img'); img.src = 'http://path/to/img'; e.dataTransfer.setDragImage(img, 0.0); }, false); Copy the code