The preface
Yesterday, I wrote a blog on my personal dynamic page, which involves uploading pictures.
Previously I used other people’s plug-ins and the Upload component of elementUI. But now it doesn’t work.
The page looks a little different, and changing the style of elementUI can be tiring.
It’s a very sad time. (Lazy!)
This is the effect of page development, much like the feeling of QQ space.
A, selection
1. Option 1: Rewrite the series yourself.
I referred to XHR and Fetch
Document Address:
XMLHttpRequest:https://developer.mozilla.org/zh-CN/docs/Web/API/XMLHttpRequest
fetch:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API
XHR is actually the most used HTTP core function, used in jquery.Ajax in the early days and axios today.
Fetch, less compatible, but the latest standard function. There’s not so much clutter anymore. Make XHR look like Ajax.
Conclusion:
In the case of XHR, you need to write the entire Ajax function yourself
Fetch is a new standard, the disadvantage is that ie does not support all systems, and edge does not support some.
Ouch: Just lazy. I don’t want to write it myself. (Also: There are a lot of things to consider when writing your own package)
2, choose axios
Well, there’s not much to say. I’m not going to pick JQ.
And I wrapped Axios myself early on to create ajax functions for my own projects. So this encapsulation is to reuse the ajax functions that you’ve wrapped.
I’m going to show you what’s going on inside axios as a whole.
The main character is the axios.upload in the bottom half
"use strict";
import Vue from "vue";
import axios from "axios";
import VueAxios from "vue-axios";
import { Notification, Loading } from "element-ui";
import apiList from "./api-list"; // const store = require("store");
import control from "@/common/control_center/index"; Vue.use(VueAxios, axios); Vue.prototype.$api= apiList; // Bind interface list data to vUE global // customize message prompt function informationletCustomMsg = {// Success message sucIfno(info) {Notification({title:"Bingo!.type: "success", message: info }); }, // Error message errIfno(info) {Notification({title:"Wrong answer?".type: "error", message: info }); }}; // Authorize functions wrap const authorize = herders => {const user_info = store.get("user_info");
if (user_info && user_info.sign) {
herders.Authorization = user_info.sign;
return herders;
} else {
returnherders; }}; // The axios function wraps const ajax = ({url ="",
loading = falseBaseURL = apilist. baseURL, data = {}, headers = {"Content-Type": "application/json; charset=UTF-8"}, // header information processing method ="get",
success = false// Success message error =trueTimeout = 1000}) => {const filter = record => {for (let key inrecord) { ! record[key] && delete record[key]; }returnrecord; }; // Interface global loading promptlet loadingInstance = "";
if(loading ! = =false) {
loadingInstance = Loading.service({
lock: true, text: loading ! = =true ? loading : "Trying to load...",
spinner: "el-icon-loading",
background: "Rgba (0, 0, 0, 0.5)"
});
}
returnNew Promise((suc, err) => {method = method.tolocalelowerCase (); // Set headers = authorize(headers); axios({ url: url, baseURL: baseURL, headers: headers, method: method, [method ==="post" ? "data" : "params"]: filter(data), timeout: timeout }) .then(response => { loadingInstance && loadingInstance.close(); // Refresh the password and determine whether to log out of the interfaceif(! control.refresh_sign_or_out(response)) { customMsg.errIfno("Data exception, log out"); err(response); } const res = response.data; /*data = {code: 0, // 0 successful, 1 failed MSG:""// Error message data:""/ / data}; * /if(res && res.code === 0) { success ! = =false &&
customMsg.sucIfno(success === true ? "Information processing successful" : success);
suc(res);
} else{ error ! = =false &&
customMsg.errIfno(res.msg ? res.msg : "Message processing failure"); err(res); } }) .catch(e => { console.log(e); loadingInstance && loadingInstance.close(); error ! = =false ? customMsg.errIfno("Abnormal interface") : false; // Catch indicates that the abnormal part of the network has nothing to do with the result returned by the back-end. Err (e); }); }); }; // Exposed Ajax functions to further encapsulate throttling and anti-shakinglet shakeTime = ""; Axios.ajax = options => {// parameter preprocessinglet shake = options.shake || false; / / is not equal tofalseDirect transfertrueOr anti-shake time // anti-shake function processingif (shake === false) {// No shaking treatmentreturn new Promise((suc, err) => {
ajax(options)
.then(e => {
suc(e);
})
.catch(e => {
err(e);
});
});
} else{// Apply anti-shake treatmentreturn new Promise((suc, err) => {
shakeTime && clearTimeout(shakeTime);
letcallNow = ! shakeTime;if (callNow) {
ajax(options)
.then(e => {
suc(e);
})
.catch(e => {
err(e);
});
}
shakeTime = setTimeout( () => { shakeTime = null; }, // see the annotation shake ===true? 700 : shake ); }); }}; Axios. upload = options => {// Concatenate data to uri address const new_url = obj => {if (obj) {
let fields = "";
for (let key in obj) {
fields = fields + `${key}=${obj[key]}`;
}
return "?" + fields;
} else {
return ""; }}; options.fdata = options.fdata ||""; / / file upload the url of the splicing address options. The success = options. Success | |"File uploaded successfully";
options.url = options.url + new_url(options.fdata);
options.headers = options.headers || {};
let header = { "Content-Type": "multipart/form-data" };
for (let i in header) {
options.headers[i] = header[i];
}
options.method = "post";
options.multiple = options.multiple || false; // Multiple files, defaultfalse// File type validation, notice the array passed in, default ["image/jpeg"."image/png"]
options.type = options.type || ["image/jpeg"."image/png"]; options.size = options.size || 0; / / file size limit, the default 0 options. The Max = options. The Max | | 5. // Upload a maximum of several files // File verification processinglet input = document.createElement("input");
input.type = "file";
options.multiple ? (input.multiple = "multiple") : "";
input.click();
return new Promise((suc, err) => {
let type = options.type;
input.addEventListener("input", watchUpload, false);
functionWatchUpload (event) {// Remove the listenerlet remove = () => {
input.removeEventListener("input", watchUpload, false); input = null; }; const file = event.path[0].files; const len = file.length; // Limit the number of filesif (len > options.max) {
err(file);
remove();
customMsg.errIfno("Number of files exceeds" + options.max);
return false;
}
let formData = new FormData();
for (leti = 0; i < len; I++) {// file size limitif(options.size ! == 0 && file[i].size / 1024 / 1024 > options.size) { err(file[i]); remove(); customMsg.errIfno(file[i].name +"File exceeds specified size");
return false; } // File type restrictionif(type.length > 0 && ! type.includes(file[i].type)) { err(file); remove(); customMsg.errIfno(file[i].name +"File type is" + file[i].type);
return false;
}
formData.append("dhtUpload", file[i], file[i].name); } options.data = formData; // Finally upload the file options.baseURL =""; ajax(options) .then(e => { suc(e); }) .catch(e => { err(e); }); }}); };export default axios;Copy the code
Start writing the upload function
Notice that it doesn’t make any difference if you use Axios directly. Don’t be fooled by my own encapsulation of Ajax.
1. Do not display input elements on the page
The original intention here is that I do not have an input element on the page but as a function. I see a lot of tutorials on the web that predefine the input node
Here I put myself in an input-based color picker. The file is similar to this
// Color pickercolorSelect() {
let input = document.createElement("input");
input.type = "color";
input.click();
input.addEventListener("input", watchColorPicker, false);
functionwatchColorPicker(event) { //console.log(event.target.value); / / remove the listening input. RemoveEventListener ("input", watchColorPicker, false);
input = ""; }}Copy the code
What is the value of the input listener
We want the value in path. Look inside the path
Notice that there is only an input element here, and we take the array of files in the input to be our file.
Let’s take a look at a single file
Here we can see the size and type of each file. We’ll use that later. For example, we limit the number of file uploads, file size and file type
3, understandFormData()
I’m just going to put the MDN document here.
https://developer.mozilla.org/zh-CN/docs/Web/API/FormData/Using_FormData_Objects
In fact, all we need to know is that it works like this.
let formData = new FormData();
formData.append("dhtUpload", file[i], file[i].name);Copy the code
Append parameter: file name, file, file name
I don’t really get it here
Take a look at a situation in the elementUI source code.
formData.append(option.filename, option.file, option.file.name);Copy the code
I don’t know much about it.
4. Learn about Ajax functions
const ajax = ({
url = "",
loading = falseBaseURL = apilist. baseURL, data = {}, headers = {"Content-Type": "application/json; charset=UTF-8"}, // header information processing method ="get",
success = false// Success message error =trueTimeout = 1000})Copy the code
These are the arguments to my Ajax function.
5. Preprocess parameters of upload function
Const new_URL = obj => {const new_url = obj => {if (obj) {
let fields = "";
for (let key in obj) {
fields = fields + `${key}=${obj[key]}`;
}
return "?" + fields;
} else {
return ""; }}; options.baseURL =""; / / individual processing, need to be compatible with previous elementui plug-in, uploading, and options. Fdata = options. Fdata | |""; / / file upload the url of the splicing address options. The success = options. Success | |"File uploaded successfully";
options.url = options.url + new_url(options.fdata);
options.loading = options.loading || true;
options.headers = options.headers || {};
options.headers["Content-Type"] = "multipart/form-data";
options.method = "post";
options.multiple = options.multiple || false; // Multiple files, defaultfalse// File type validation, notice the array passed in, default ["image/jpeg"."image/png"]
options.type = options.type || ["image/jpeg"."image/png"]; options.size = options.size || 0; / / file size limit, the default 0 options. The Max = options. The Max | | 5. // Upload a maximum of several filesCopy the code
Looks like a lot of parameters. Not much.
Analyze:
Fdata: Because the file upload address must be diverse. But we also need to pass some information outside of the file. You can actually concatenate parameters in the address bar. The back end is also available.
New_url and fData exist for this purpose.
Success: indicates a simple prompt for file uploading. This is because the Ajax wrapper wrapped the message inside, but it succeeded without the message by default.
Headers: Not much to say about this, but to ensure that headers might exist elsewhere, it is set this way. Content-type: “multipart/form-data” this is required
Loading: A loading prompt is displayed in full screen during file loading
Method: The value must be Post
Multiple: The missing point here is to control whether a file is multiple or single file uploaded
Type: file type control. We pass in an array. Default controls image files. What defaults are passed to restrict these types
Size: limits the size of each file. 0 does not limit the size
Max: Limit the number of files. Single files are meaningless
6. Create the Input object and preprocess the parameters.
// File validation processinglet input = document.createElement("input");
input.type = "file";
options.multiple ? (input.multiple = "multiple") : "";
input.click();Copy the code
Multiple = multiple; multiple = multiple
7, create input listener, get file object information, pay attention to the outer layer with promise encapsulation
I’m going to put the whole control part here and break it down
return new Promise((suc, err) => {
let type = options.type;
input.addEventListener("input", watchUpload, false);
functionwatchUpload(event) { //console.log(event); // Remove the listenerlet remove = () => {
input.removeEventListener("input", watchUpload, false); input = null; }; const file = event.path[0].files; const len = file.length; // Limit the number of filesif (len > options.max) {
remove();
customMsg.errIfno("Number of files exceeds" + options.max);
err(file);
return false;
}
let formData = new FormData();
for (leti = 0; i < len; I++) {// file size limitif(options.size ! == 0 && file[i].size / 1024 / 1024 > options.size) { remove(); customMsg.errIfno(file[i].name +"File exceeds specified size");
err(file[i]);
return false; } // File type restrictionif(type.length > 0 && ! type.includes(file[i].type)) { remove(); customMsg.errIfno(file[i].name +"File type is" + file[i].type);
err(file);
return false;
}
formData.append("dhtUpload", file[i], file[i].name); } options.data = formData; Then (e => {suc(e); }) .catch(e => { err(e); }); // Clear the listener if there is no problem. remove(); }});Copy the code
8, get the file array information, note that you do not select the file will not trigger the listener
//console.log(event); // Remove the listenerlet remove = () => {
input.removeEventListener("input", watchUpload, false); input = null; }; const file = event.path[0].files; const len = file.length; // Limit the number of filesif (len > options.max) {
remove();
customMsg.errIfno("Number of files exceeds" + options.max);
err(file);
return false;
}
let formData = new FormData();Copy the code
Look at the notes here and you know what I did.
First: I get an array of files. And take care of the removal listeners in advance, as they will be used in many places.
Second: I judge the file limit. If so, the promise (err(file) in the code) returns an error; And unlog the listener
Third: Declare the formData object first
9. Restrict each element and add to formData
for (leti = 0; i < len; I++) {// file size limitif(options.size ! == 0 && file[i].size / 1024 / 1024 > options.size) { remove(); customMsg.errIfno(file[i].name +"File exceeds specified size");
err(file[i]);
return false; } // File type restrictionif(type.length > 0 && ! type.includes(file[i].type)) { remove(); customMsg.errIfno(file[i].name +"File type is" + file[i].type);
err(file);
return false;
}
formData.append("dhtUpload", file[i], file[i].name);
}
options.data = formData;Copy the code
It should be pretty obvious here. I walk through each file and impose limits on file size and file type.
Finally, the passed formData data is assigned to the Ajax data object
10, all is well, call the original package ajax
Then (e => {suc(e); }) .catch(e => { err(e); }); // Clear the listener if there is no problem. remove();Copy the code
Three, complete use.
this.axios
.upload({
url: this.$api.static().upload_pictures
})
.then(e => {
console.log("Success", e);
})
.catch(e => {
console.log("Error", e);
});Copy the code