Introduction to the

Front-end upload and download is usually not often used, even if used may be the previous module or third-party library has been written, introduced can be used. But I think as front-end development, file upload and download is very necessary to understand clearly.

This article mainly describes the front-end File upload and download, here may involve some front-end binaries, such as ArrayBuffer, TypedArray, DataView, Blob, File, Base64, FileReader, etc. If this is not clear, you can first read the author of the front-end binary to clarify the article.

download

There are many different ways to download, and each has its own characteristics.

Hyperlink download

Using hyperlinks to complete our front-end download is the most common way. Its main use of the window. The URL. CreateObjectURL (blob) method to generate a blob URL, then blob URL assigned to link href attribute, and then click on the link to download.

A simple way of thinking about it is to convert an object of type file or Blob to a UTF-16 string and store it in memory under the document of the current operation.

The method used to generate the BLOb URL is url.createObjecturl (file/blob). The clearing can only be done by the page unload() event or manually using the URL. RevokeObjectURL (objectURL).

The Download attribute is used to name downloaded files, but note the compatibility of the Download attribute.

Next, I’ll simulate the back end returning ArrayBuffer and Blob objects for hyperlinked downloads.

The backend returns an ArrayBuffer

function aDownload1() {
  // The simulated backend returns an ArrayBuffer
  const str = "hello randy!";
  let ab = new ArrayBuffer(str.length);
  let ia = new Uint8Array(ab);
  for (let i = 0; i < str.length; i++) {
    ia[i] = str.charCodeAt(i);
  }

  const a = document.createElement("a");
  // Set the file name to test
  a.download = "test";
  // Convert an ArrayBuffer to a bloB
  const blob = new Blob([ia], { type: "text/plain" });
  // Generate a BLOb URL. You can use Blob objects or File objects
  a.href = window.URL.createObjectURL(blob);
  a.style.display = "none";
  document.body.appendChild(a);
  a.click();
  // Free memory
  window.URL.revokeObjectURL(a.href);
  // Remove element A
  document.body.removeChild(a);
}
Copy the code

The back end returns a Blob

function aDownload2() {
  // The simulated backend returns a Blob
  const blob = new Blob(["hello"."randy"] and {type: "text/plain" });

  const a = document.createElement("a");
  // Set the file name to test
  a.download = "test";
  // Generate the BLOb URL directly. You can use Blob objects or File objects
  a.href = window.URL.createObjectURL(blob);
  a.style.display = "none";
  document.body.appendChild(a);
  a.click();
  // Free memory
  window.URL.revokeObjectURL(a.href);
  // Remove element A
  document.body.removeChild(a);
}
Copy the code

ShowSaveFilePicker API to download

ShowSaveFilePicker is a new API that calls this method to display a file selector that allows the user to choose a save path.

const FileSystemFileHandle = Window.showSaveFilePicker(options);
Copy the code

The showSaveFilePicker method supports an optional argument of an object type that can contain the following attributes:

  1. ExcludeAcceptAllOption: Boolean type. Default value is false. By default, the selector should include an option not to apply any file type filters (enabled by the types option below). Setting this option to true means that the types option is not available.

  2. Types: Array type, representing the list of file types allowed to be saved. Each entry in the array is a configuration object containing the following properties:

  • Description (Optional): Describes the types of files allowed to be saved.
  • accept: is an object, of that objectkey 是 MIMEType and the value is a list of file extension names.
  1. suggestedNameRecommended file name.
async function download3(blob, filename) {
  try {
    const handle = await window.showSaveFilePicker({
      suggestedName: filename,
      types: [{description: "text file".accept: {
            "text/plain": [".txt",}}, {description: "jpeg file".accept: {
            "image/jpeg": [".jpeg"],},},],});const writable = await handle.createWritable();
    await writable.write(blob);
    await writable.close();
    return handle;
  } catch (err) {
    console.error(err.name, err.message); }}function showSaveFilePickerDownload() {
  // Simulate blob files
  const blob = new Blob(["hello"."randy"] and {type: "text/plain" });

  download3(blob, "test.txt");
}
Copy the code

When you click download, the following selection screen will appear, which will show your suggested file name and file type selection.

The showSaveFilePicker API allows you to select the file download directory, select the file format, and change the file name. Unfortunately, the API isn’t very compatible at the moment.

FileSaver download

FileSaver. Js is a solution for saving files on the client and is ideal for Web applications that generate files on the client.

Compatibility is as follows

The main thing to remember about Filesaver.js is its saveAs method.

FileSaver.saveAs(
 Blob/File/Url, 
 optional DOMString filename, 
 optional Object { autoBom }
)
Copy the code

SaveAs method supports three parameters:

The first parameter indicates that it supports Blob/File/Url.

The second parameter indicates the name of the file (optional).

The third parameter indicates the configuration object (optional). Set {autoBom: true} if you want fliesaver.js to automatically provide Unicode text encoding prompt byte order tokens. Note that this can only be done if charset= UTF-8 of blob type is set.

The installation

npm install file-saver --save
Copy the code

The blob data source

const blob = new Blob(["Hello, world!"] and {type: "text/plain; charset=utf-8"});
FileSaver.saveAs(blob, "helloworld.txt");
Copy the code
const canvas = document.getElementById("my-canvas");
canvas.toBlob(function(blob) {
    saveAs(blob, "prettyimage.png");
});
Copy the code

The file data source

const file = new File(["Hello, world!"] and {type: "text/plain; charset=utf-8"});
FileSaver.saveAs(file, "helloworld.txt");
Copy the code

Web linked data source

FileSaver.saveAs("https://httpbin.org/image"."image.jpg");
Copy the code

Jszip compressed download

Jszip can convert downloaded files to ZIP format.

Jszip does not have its own download function, it only provides the function of zip file compression, we still need to use the aforementioned FileSaver.

The installation

npm install jszip
Copy the code

use

// Create a JSZip object
var zip = new JSZip();

// Add the file to the JSZip object you created earlier
zip.file("Hello.txt"."Hello World\n");

// Generate JSZip file
zip.generateAsync({type:"blob"}).then(function(content) {
  // Filesaver.js is required
  FileSaver.saveAs(content, "example.zip");
});
Copy the code

See the official documentation for more information on how to use JsZip

Attachment download

When it comes to attachment download, many small partners may not understand, the following author gives an example you will understand.

We usually enter the link address of the image in the browser, why some images are preview and others are download directly?

This link in your browser to open direct preview is https://p9-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/ab5e763e993f4bfab3c2ce3ef2935ec6~tplv-k3u1fbpfcp-waterm ark.image

Open this link in your browser is direct download http://pic.96weixin.com/ueditor/20200511/1589185236200665.jpg?x-oss-process=image/resize, m_lfit, w_120

This involves attachment downloading.

We can set the Content-Disposition response header to indicate whether the Content of the response is presented inline or downloaded and saved locally as an attachment. Filename Specifies the name of the file to download.

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="mouth.png"
Copy the code

Open the console and you’ll see that our second image above has the Content-Disposition response header set, so we’ll download the image directly as an attachment after we enter the image link.

upload

In the upload section, either way, you get the file object and then transfer it using the FormData object.

Single file upload

<input id="uploadFile1" type="file" accept="image/*" />
Copy the code
const upload = () = > {
  // Get the uploaded input element
  const uploadFileEle = document.querySelector("#uploadFile1");
  // Get the file
  const files = uploadFileEle.files;
  let formData = new FormData();
  formData.append(fieldName, files[0]);
  // make a request
  // axios.post(url, formData)
}
Copy the code

Multi-file upload

For multi-file uploads, we only need to tweak it slightly. Add a multiple attribute to the input element to support multiple file uploads.

<input id="uploadFile2" type="file" accept="image/*" multiple />
Copy the code

For JS, we need to add our files in a loop within the form.

const upload = () = > {
  // Get the uploaded input element
  const uploadFileEle = document.querySelector("#uploadFile2");
  // Get the file
  const files = uploadFileEle.files;
  let formData = new FormData();
  Object.values(files).forEach((file, i) = > {
    formData.append('file' + i, file);
  });
  // make a request
  // axios.post(url, formData)
}
Copy the code

Folder upload

For folder uploads, we only need to tweak it slightly. Add a webkitDirectory attribute to the input element to indicate a folder upload.

The compatibility of this property is as follows. Note that Internet Explorer does not support this property at all.

<input id="uploadFile3" type="file" accept="image/*" webkitdirectory />
Copy the code

For JS, we need to add our files in a loop within the form.

const upload = () = > {
  // Get the uploaded input element
  const uploadFileEle = document.querySelector("#uploadFile3");
  // Get the file
  const files = uploadFileEle.files;
  let formData = new FormData();
  Object.values(files).forEach((file, i) = > {
    formData.append('file' + i, file);
  });
  // make a request
  // axios.post(url, formData)
}
Copy the code

If you upload in folder mode, there will be a little prompt after selecting folder, as follows

And we can see the relative path of the File in the File object with the webkitRelativePath property.

Jszip compressed upload

Compressed upload is to compress a file into a compressed package and upload it to the server. For compression, use the JsZip library we introduced earlier.

Below I use the way of folder upload example.

<input id="uploadFile4" type="file" accept="image/*" webkitdirectory />
Copy the code
function generateZipFile(
  zipName,
  files,
  options = { type: "blob", compression: "DEFLATE" }
) {
  return new Promise((resolve, reject) = > {
    // Create a JSZip object
    const zip = new JSZip();
    Object.values(files).forEach((file, i) = > {
      // Looping adds the file to the JSZip object you created earlier
      zip.file("file" + i, file);
    });
    // Generate JSZip file
    zip.generateAsync(options).then(function (blob) {
      zipName = zipName || Date.now() + ".zip";
      const zipFile = new File([blob], zipName, {
        type: "application/zip"}); resolve(zipFile); }); }); }async function uploadFile() {
  // Get the uploaded input element
  const uploadFileEle = document.querySelector("#uploadFile4");
  // Get the file
  const files = uploadFileEle.files;
  // Get the relative path
  let webkitRelativePath = fileList[0].webkitRelativePath;
  // Get the folder name, used as the zip package name
  let zipFileName = webkitRelativePath.split("/") [0] + ".zip";
  let zipFile = await generateZipFile(zipFileName, fileList);
  
  let formData = new FormData();
  formData.append('zipfile', zipFile);
  // make a request
  // axios.post(url, formData)
  
}
Copy the code

Drag and drop to upload

To implement drag-and-drop uploads, we need to understand drag-and-drop events. Such as the Drag, Dragend, Dragenter, Dragover, or drop event.

  • dragenter: triggered when an element or selected text is dragged to a releasable target
  • dragover: Fires when an element or selected text is dragged onto a releasable target (every 100 milliseconds);
  • dragleaveEmitted when a drag element or selected text leaves a releasable target;
  • drop: Emitted when an element or selected text is released on a releaseable target.

You can check out the MDN official documentation about drag and drop. I won’t go into details here.

The core of drag-and-drop upload is to retrieve the list of files from the Files property of the DataTransfer object, and then upload using FormData.

The core code

dropAreaEle.addEventListener("drop", handleDrop, false);

function handleDrop(e) {
  // Get the list of files on the dataTransfer object
  const files = e.dataTransfer.files;
  let formData = new FormData();
  Object.values(files).forEach((file, i) = > {
    formData.append("file" + i, file);
  });
  // make a request
  // axios.post(url, formData)
}
Copy the code

Copy and paste upload

For copy and paste we first need to understand the Clipboard object.

We can retrieve the ClipBoard object via navigator.clipboard, and then retrieve the content via navigator.clipboard.read(). But for incompatible items we need to access the contents of the clipboard via E.clipboardData. items.

The following example is to upload an image from a clipboard.

onst IMAGE_MIME_REGEX = /^image\/(jpe? g|gif|png)$/i;
const uploadAreaEle = document.querySelector("#uploadArea");

// Listen for the paste event
uploadAreaEle.addEventListener("paste".async (e) => {
  e.preventDefault();
  const files = [];
  if (navigator.clipboard) {
    let clipboardItems = await navigator.clipboard.read();
    for (const clipboardItem of clipboardItems) {
      for (const type of clipboardItem.types) {
        if (IMAGE_MIME_REGEX.test(type)) {
          const blob = awaitclipboardItem.getType(type); files.push(blob); }}}}else {
    const items = e.clipboardData.items;
    for (let i = 0; i < items.length; i++) {
      if (IMAGE_MIME_REGEX.test(items[i].type)) {
        letfile = items[i].getAsFile(); files.push(file); }}}// With files we can use FormData to upload
  let formData = new FormData();
  files.forEach((file, i) = > {
    formData.append("file" + i, file);
  });
  // make a request
  // axios.post(url, formData)
});
Copy the code

About the FormData

The previous uploads all involve FormData. Many friends may not understand FormData, so the author will explain the relevant API of FormData in detail here.

FormData we can think of as the JS version of a form. The function is similar to our HTML form.

// Create an empty object using the FormData constructor
const formdata = new FormData();
// Append data with the append() method
formdata.append("name"."randy");
// Use the get method to read the value
console.log(formdata.get("name"));//randy
// Use the set method to set the value
formdata.set("name"."demi");
console.log(formdata.get("name"));//demi
// Get all values whose key is age and return values of array type
formdata.getAll("age");
// Check whether data with key as name is included
console.log(formdata.has("name"));//true
// Delete key name
formdata.delete("name");
Copy the code

Instead of creating a new formData, we can initialize it based on an existing form.

<form id="myForm">Name:<input type="text" name="name"  value="randy">
</form>
Copy the code
// Get the form element in the page based on the ID
const myForm = document.querySelector("#myForm");
// Initialize formData with the obtained form elements as parameters
const formdata=new FormData(myForm);
console.log(formdata.get("name"));// randy
Copy the code

FormData, similar to Object, supports keys, values, and entries

formData.keys();
formData.values();
formData.entries();
Copy the code

More details about formData can be found in the OFFICIAL MDN documentation

Ali oss upload and download

In addition to uploading and downloading on our own server as described above, we may also encounter uploading and downloading on third-party servers, such as OSS, which we also need to understand. For our front-end, focus on the OSS node documentation.

Refer to the article

For file downloads, it’s enough to understand these nine scenarios

File upload. It’s enough to understand these 8 scenarios

Afterword.

This article is the author’s personal study notes, if there are fallacies, please inform, thank you! If this article has been helpful to you, please click the “like” button. Your support is my motivation to keep updating.