preface

Note: Please use this Token: 1562835370187 to access Demo, or click access.

This article through the implementation of (text/file) drag preview function comprehensive, in-depth analysis of the whole process involved in the object and ITS API, enhance our understanding and application of file data. The content of the presentation includes:

  • DataTransferObject introduction and API application
  • Drag event type and application
  • Intercept drag information
  • FileandBlobThe object is introduced
  • Picture preview function
  • Data URL and Blob URL

The DataTransfer object

A DataTransfer object is used to hold data that is dragged in a drag-and-drop operation. It can contain one or more data items, each of which can have one or more data types.

Properties of DataTransfer objects are divided into standard properties and Gecko properties. The standard properties are supported by all modern browsers, while the Gecko properties are only supported by gecko-kernel browsers. Accordingly, DataTransfer methods can be divided into standard methods and GECko methods.

Standard properties of the DataTransfer

The property name The values note
dropEffect none, copy, link, move Gets/sets the current drag-and-drop operation type
effectAllowed CopyLink, copyMove, link, linkMove, move, all or uninitialized(default) Gets/sets the types of all drag operations allowed
files Arrray List of dragged files
items DataTransferItemList object Read-only, list of dragged data
types Arrray Read-only, a list of data formats set (via the setData API) in the dragStart event

Standard method of DataTransfer

The method name parameter note
clearData([format]) Forma: [Optional] Indicates the data type Clears all drag data of the specified type
getData(format) Format: [mandatory] Data type Gets drag data of the specified type, or an empty string if there is no data
setData(format, data) Format: [must] Data type, data: [must] Data added to the drag object Sets the data of the given type. If this type of data does not exist, it is added to the end of the list; If it exists, replace it.
setDragImage(img, xOffset, yOffset) Img: [must] image element; XOffset: [required]X offset; YOffset: [mandatory] Y-offset Custom drag images

For Gecko properties and methods of DataTransfer objects, see here.

Drag events

When a user drags an element or text, a drag event is triggered every few hundred milliseconds. Drag event types are:

document.addEventListener('dragstart', evt => {
    console.log('dragstart');    
});
document.addEventListener('dragenter', evt => {
    console.log('dragenter');    
});
document.addEventListener('dragleave', evt => {
    console.log('dragleave');    
});
document.addEventListener('dragover', evt => {
    event.preventDefault();
    console.log('dragover');    
});
document.addEventListener('drop', evt => {
    console.log('drop');    
});
document.addEventListener('dragend', evt => {
    console.log('dragend');    
});
Copy the code

Drag events are bound to elements, and if the code in the example above is bound to the Document object, drag events for the entire document page take effect. In practice, however, we tend to hijack drag and drop operations on an input area, such as:

$inputBox.addEventListener'drop', evt) => {
  evt.preventDefault()
  console.log('drop')}, {capture: false.passive: false
})
Copy the code

In particular, drag events have a strict firing sequence:

Drag the effect

The DataTransfer object provides two properties, dropEffect and Effectalhoward, that allow us to customize the type of mouse we use during our drag. The value of dropEffect is restricted by effectalhoward, and only the values allowed by Effectalhoward can be set.

effectAllowed

EffectAllowed can only be set in dragstart events, and will not be set in other events. Meanings of different values:

  • None: Item is prohibited from dragging
  • Copy: You can copy the source project in a new location
  • CopyLink: Allows copy and link operations
  • CopyMove: Allows copying and moving operations
  • Link: You can create a link to the source project in a new location
  • LinkMove: Allows linking and moving operations
  • Move: You can move an item to a new location
  • All: Allows all operations
  • Uninitialized: The default value. The effect is the same as that of all
document.addEventListener('dragstart', (e) => {
    e.dataTransfer.effectAllowed = 'none'
}, {
    capture: false.passive: false
})
Copy the code

When set as above, elements/text on the document will be prevented from dragging and dropping. But it can still trigger a series of drag events other than drop.

dropEffect

The value of dropEffect is restricted by effectalhoward, and only the values specified by Effectalhoward are allowed. Possible values are move, copy, link, and None. DropEffect is generally set in dragenter and dragover events, and does not take effect in other events.

$Ele.addEventListener('dragover', (e) => {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'move|move|copy|link'
}, {
    capture: false.passive: false
})
Copy the code

Click here to play: Drag operation mouse type demo

setDragImage

This API allows you to customize the background image of the mouse during a drag operation. This method must be called in dragstart:

const img = new Image()
img.src = './bg.png'
document.addEventListener('dragstart', (e) => {
    e.dataTransfer.setDragImage(img, 5.5)}, {capture: false.passive: false
})
Copy the code

As shown below, drag the text to the input box and a background image will follow under the mouse:

DataTransferItem object

Before introducing drag interception, it’s important to understand the dataTransferItem object. The dataTransferItem object represents a dragged data item, such as dragged text, images, and so on. It has two read-only properties that describe data types and a series of methods for converting dataTransferItem data to data of the corresponding type (string, file, and so on). The following table:

Properties/methods parameter describe
kind read-only Drag item data properties: string/file
type read-only Drag item data MIME type: image/ PNG, etc
getAsFile() / Read drag item data as a File and return a File object, or null for non-file data.
getAsString(call) Call (STR) => STR Read drag data as a string, and get string data in the callback function.

The DataTransferItemList object, which is an array-like object (with a length attribute, read only, There are also apis like Add (), remove(), and clear()).

Intercept drag data

Hijacking of drag data is generally handled in the Dragstart and drop phases, because the events in these two phases are one-off and do not trigger more than once, causing no performance problems. For example, use setData to set a fixed copy to overwrite the dragged text content:

document.addEventListener('dragstart', e => {
  e.dataTransfer.setData('text/plain'.'Copy expected to be covered')}, {capture: false.passive: false
})
Copy the code

In the drop phase we can intercept drag data and do secondary processing. However, there are some differences for different types of data interception.

String data

For string data, the easiest way to get it is through the getData method (which cannot get file-like data). For example, get the plain text content of a drag:

$Ele.addEventListener('drop', (e) => {
  e.preventDefault()
  console.log(e.dataTransfer.getData('text'))}, {capture: false.passive: false
})
Copy the code

This method gets the plain text content of the drag:

console.log(e.dataTransfer.getData('text/plain'))
Copy the code

This method gets the content of the dragged document’s DOM node and its ancestor node:

dataTransferItem

File type data

The DataTransfer object has a files property that stores the list data of a dragged file. The data item is a File object data that can be fetched directly.

$Ele.addEventListener('drop', (e) => {
  e.preventDefault()
  const files = e.dataTransfer.files || []
  if(files.length) {
    // do something...}},false)
Copy the code

From the Items property

The items attribute is a DataTransferItemList object, which is retrieved one by one through the for loop and used to determine the value of the dataTransferItem’s Kind attribute:

const transferItems = e.dataTransfer.items
for(let i = 0; i < transferItems.length; i++) {
  const item = transferItems[i]
  if(item.kind === 'string') { // Process string data
    item.getAsString(str= > console.log(str))
  } else if (item.kind === 'file') { // Process file data
    const file = item.getAsFile()
    // ...}}Copy the code

After capturing drag data in the above way, we can preview or send file data as needed.

File&Blob overview

The getAsFile API is used to retrieve the dragged File and return a File object. This contains information about the file type (image/ PNG, etc.), name, and size. A File object is a special type of Blob that inherits the properties and methods of a Blob. The main properties used in a File are:

attribute note
name The file name
size The file size
type File MIME type
lastModified When the file was last modified

Blob is an immutable file-like object that represents raw data. It has two read-only properties, type and size. You can read the data in the Blob using FileReader and Response. For example, an image file is read by FileReader in different data formats:

  • Read in Data URL format
const reader = new FileReader()
  reader.addEventListener("load", () = > {console.log(reader.result)
  }, false)
reader.readAsDataURL(file)
// reader.readAsArrayBuffer(file)
// reader.readAsText(file[, encoding])
Copy the code

Return a string of data:[MIME type]; The base64 encoded string at the beginning reads the data URL data commonly used for image preview:

  • In order toArrayBufferFormat read, return oneArrayBufferobject

    Read theArrayBufferThe data is typically used for secondary processing of images, such as converting jEPG images to PNG.

  • The value is read in Text format. The default value isutf-8To read the text content (the image read this way, will be garbled)

Implement image preview

Now, based on the captured data, we need to go ahead and implement: if it’s an image, preview it. There are two ways to preview Data URLS and Blob urls.

File&Blob overview
FileReader.readAsDataURL()

createObjectURL

The URL object can be used to construct, parse, and encode urls. It provides a static method createObjectURL(), which takes arguments only to objects of the File, Blob, and MediaSource types, and converts file-like objects into URL strings. Blob: http://localhost:8080/c61a0313-2e45-4adc-a40e-fbbffd4c84ba), the string pointed to the corresponding object reference (file).

// We intercepted the data from the file object
const { name, size } = file
const url = URL.createObjectURL(file)
this.previewObj = {
    name,
    size,
    src: url
}
Copy the code

callcreateObjectURL()The method has two characteristics:

  • indocumentBefore unloading,URLObject instances always keep references to source objects;
  • Execute the same object multiple timescreateObjectURLMethod, which generates different INSTANCES of the URL object.

From a specification and memory management perspective, each time createObjectURL is executed, we need to manually free the memory (which doesn’t really matter in practice) :

// Unload the reference to the URL instance when the file is ready to load
img.onload = function() {
  URL.revokeObjectURL(this.src);
}
Copy the code

The difference between Data urls and Blob urls

  • So the Data URL representsbase64The Blob URL represents a reference to an (in-memory/local) image file (this is the essential difference);
  • The transformation of Data urls is asynchronous, while Blob urls are synchronous. In the case of large files or batch processing, Blob URL is faster than Data URL.
  • Data URL strings (thousands of characters) are much longer than BlobURL strings (less than 100 characters). Blob URLS are better than Data urls in terms of web page performance.
  • Data urls are accessible across devices (browsers), Blob urls are only valid within the current Web application, not across applications (although copying the Blob URL to the browser address bar is still accessible without uninstalling the Document). Data urls are superior to Blob urls in terms of portability.

In the end,

Reference:

  • DataTransfer related MDN
  • Drag a sacrificial Black Goat -DataTransfer object
  • Rendering Image Previews Using Object URLs vs. Base64 Data URIs In AngularJS