Front-end file download and drag-and-drop upload

Keywords: Javascript axios Attribute

demand

  1. Add Download Sample Button to the page
  2. To achieve a region can drag and drop upload word files, limit file size to 2MB and file type, display progress bar, and support canceling upload.

File download

What the business requires is that the sample be placed in a static folder without requiring a background request. For this scenario, the author will introduce three methods: window.open, form submission and a tag download. The author will compare the three methods by downloading img and word documents.

The structure of dom is constructed as follows:

<button onClick={this.windowOpen}>window.open</button>
<button onClick={this.formSubmit}>formSubmit</button>
<button onClick={this.aDownload}>aDownload</button>

Method 1: Use window.open:

import gakkiURL from './gakki.jpg';
import wordURL from './wordURL.doc';
windowOpen = () => {
    window.open(gakkiURL);
    //window.open(wordURL);
}

When requesting two kinds of files, the method is shown as follows:

Img: Open a new web page, and then display the corresponding img pictures.

word: Download the file.

Method 2: Subit using form form:

formSubmit = () => {
    let form = document.createElement('form');
    form.method = 'get';
    form.action = gakkiURL;
    //form.action = wordURL;
    //Form. target ='_blank'; // form new page
    document.body.appendChild(form); // form forms are added to the dom tree before submitting
    form.submit();
    document.body.removeChild(form);
}

When requesting two kinds of files, the method is shown as follows:

img: form opens url and displays pictures on the current page when target is not set.

word: Download the file.

As can be seen from the above two methods, browsers will choose different processing methods for different MIME types when requesting the corresponding url. When requesting img, txt and other formats, the browser opens the corresponding file instead of downloading it. What if you want these formats to be downloaded as well? At this point, method three is needed.

Method 3: Using label a:

// Use a label
aDownload = () => {
    const a = document.createElement('a');
    a.href = gakkiURL;
    //a.href = wordURL;
    //a.download = 'gakki.jpg';
    a.click();
}

The a tag performs the same two methods without the download attribute, and after adding the download attribute, it can successfully trigger the download of img and other formats.

download:

This property can set a value to specify the name of the download file. The allowable values are unlimited. The browser will automatically detect the correct file extension and add it to the file (.img,.pdf,.txt,.html, etc.).

The final comparative effect:

File drag and drop upload

File upload

The common method is to use the input tag of type="file" to trigger the download, and then use formData to transfer the data. The code is as follows:

// Click Upload Document
handleClick = () => {
    const input = document.createElement('input');
    input.type = 'file';
    input.accept = 'application/msword, application/vnd.openxmlformats-officedocument.wordprocessingml.document'; // MIME Types for word Files
    input.onchange = (e) => {
        const file = e.target.files.items(0);// files[0] will do as well.
        console.table(file);
        // Check document format
        if (!this.checkDocument()) {
            e.target.value = '';
            return;
        }
        // Upload document
        this.uploadDocument(file);
    };
    input.click();
};

accept: Indicates the MIME type of the file that input accepts. The MIME types corresponding to. doc and. docx are indicated in the source code.

fileList objects can be indexed by items or arrays to obtain the corresponding file objects. The common attributes of file objects are lastModified, type, name, and size. These attributes allow you to customize the document format.

The code checkDocument for checking documents is as follows:

// Document inspection
checkDocument = file => {
    const accept = ['.doc', '.docx'];
    const index = file.name.lastIndexOf('.');
    if (index < 0 || accept.indexOf(file.name.substr(index).toLowerCase()) < 0) { // Check file type
        Message.error('This file format is not supported for the time being.');
        return false;
    }
    if (file.size > 2 * 1024 * 1024) { // Check file size
        Message.error('Documents greater than 2 MB,Upload failure');
        return false;
    }
    return true;
};

Then upload the document uploadDocument:

// Upload document
uploadDocument = file => {
    const index = file.name.lastIndexOf('.');
    const fileName = file.name.slice(0, index);
    const formData = new FormData();
    formData.append('file', file);
    // Upload by ajax, fetch, axios, etc.
    ...
};

After uploading the document, you need to get the progress bar of the upload progress display. The following sections describe the support of ajax, fetch and axios for the progress event respectively.

Ajax

Native support for progresses events can be used to obtain upload progress and download progress, respectively, xhr.upload.onprogress and xhr.onprogress events. The code is as follows:

xhr.upload.onprogress = ev => console.log((ev.loaded / ev.total) * 100)

In addition, you can use xhr.abort() to cancel file upload.

Fetch

Programs events are not supported, so upload progress cannot be retrieved. However, the author found that because res.body is a readable byte stream object, the download progress can be obtained by using the getReader() attribute supported by res.body object. Refer to the specific literature. jakearchibald.com/2016/stream…  . The code here has nothing to do with the need for uploading, and can be skipped directly as an extension of fetch.

The res.body.getReader() method is used to read the original byte stream of the response, which can be read circularly until the body content transfer is completed.

fetch(url, options).then(res => {
    let reader = res.body.getReader();
    let loaded = 0;

    // The read() method returns a promise and resolve s when the value is accepted.
    reader.read().then(function processResult(result) {
        // The result object has two attributes:
        // done: true at completion
        // value data
        if (result.done) { // Exit the loop at completion
            console.log("Fetch complete");
            return;
        }

        loaded += result.value.length;// Length in bytes
        console.log('Received', loaded, 'bytes of data so far');

        // Cyclic reading
        return reader.read().then(processResult);
    });
});

Axios

Upload and download are achieved through onUpload Progress and onDownload Progress.

onUploadProgress(ev) => {
    length = Math.round((ev.loaded / ev.total) * 100);
    console.log(length);
}

axios cancels requests using cancel token

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios.get(url, {
  cancelToken: source.token
})

source.cancel();//Cancellation request

summary

ajax and axios both support progresses events well, and fetch is not available here due to lack of support for progresses events.

Drag and drop events

After realizing the functions of clicking upload, getting upload progress and canceling upload, the next thing to be done is dragging upload. Before I implement this, I will introduce the relevant events. The first is the events that occur when dragging an object: onDragStart, onDrag and onDragEnd, which are related to the object being dragged.

onDragStart: Drag Start

onDrag: Continuous trigger in drag

onDragEnd: Drag ends, triggering events whether or not they can be placed

Then there are events to trigger when placing files: onDragEnter, onDragOver, onDragLeave and onDrop, which are related to the area to be dragged into.

onDragEnter: Triggered when a dragged object enters

onDragOver: Continuous triggering of dragged objects as they drag in the region

onDragLeave: Triggered when a dragged object leaves the area

onDrop: Triggered when a dragged object is placed in an area

In order to drag word documents in a project, you need to cancel the default onDragEnter and onDragOver events on the container because:

The event listener dragenter or dragover event is used to represent a valid drop target, where the drag item may be dropped. Most areas of a web page or application are not valid locations for drop data. Therefore, drop is not allowed by default processing of these events.

If you want to allow drop, you must prevent default processing by canceling events. You can do this by returning false from the attribute-defined event listener or by calling the preventDefault method of the event. The latter may be possible in a function defined in a separate script.

The dom structure is as follows:

<div
    styleName="dropbox"
    onDragOver={this.preventDefault}
    onDragEnter={this.preventDefault}
    onDrop={this.handleDrop}
    >
    <div styleName="word-img" />
    {this.renderBtnByUpload(this.state.uploadStatus)} // Upload status determines whether to upload files or cancel uploads
</div>

After dragging and dropping the file into the content area, the file information can be obtained through the dataTransfer object. The final handleDrop event is as follows:

// Drag and drop uploads
handleDrop = (e) => {
    const file = e.dataTransfer.files[0];
    if (e.dataTransfer.files.length > 1) {
        Message.error('Only one upload is supported word file');
        return;
    }
    if (!this.checkDocument(file)) {
        // Upload failure exits directly
        e.target.value = '';
        return;
    }
    this.uploadDocument(file); // Upload files
}

summary

Ultimately, the overall idea of implementation is to build a container for placing files, then cancel the default onDragOver and onDragEnter events for the container, get the files and upload them through dataTransfer.files when dragging files into the container, take the length of the programs events provided by ajax or axios, transfer the length to the progress Bar component, and finally display them. Come out.

Links to the original text: https://www.jianshu.com/p/01c...

Posted by MindOverBody on Sat, 18 May 2019 15:52:06 -0700