概述
参考:https://www.php.cn/js-tutorial-395168.html以及element-ui的图片上传源码。图片上传虽然是多选,但是实际上传图片上传的时候 仍然是一张一个一张一个请求上传的。
1. 新建axios.js文件,实现ajax文件上传:
//新建axios.js文件,实现ajax文件上传
export default function sendRequest(option) {
upload(option);
}
function upload(option) {
if (typeof XMLHttpRequest === 'undefined') {
return;
}
const xhr = new XMLHttpRequest();
const action = option.action;
if (xhr.upload) {
xhr.upload.onprogress = function progress(e) {
if (e.total > 0) {
e.percent = e.loaded / e.total * 100;
}
option.onProgress(e);
};
}
const formData = new FormData();
if (option.data) {
Object.keys(option.data).forEach(key => {
formData.append(key, option.data[key]);
});
}
formData.append(option.filename, option.file, option.file.name);
xhr.onerror = function error(e) {
option.onError(e);
};
xhr.onload = function onload() {
if (xhr.status < 200 || xhr.status >= 300) {
return option.onError(getError(action, option, xhr));
}
option.onSuccess(getBody(xhr));
};
xhr.open('post', action, true);
if (option.withCredentials && 'withCredentials' in xhr) {
xhr.withCredentials = true;
}
const headers = option.headers || {};
for (let item in headers) {
if (headers.hasOwnProperty(item) && headers[item] !== null) {
xhr.setRequestHeader(item, headers[item]);
}
}
xhr.send(formData);
return xhr;
}
function getError(action, option, xhr) {
var msg = void 0;
if (xhr.response) {
msg = xhr.status + ' ' + (xhr.response.error || xhr.response);
} else if (xhr.responseText) {
msg = xhr.status + ' ' + xhr.responseText;
} else {
msg = 'fail to post ' + action + ' ' + xhr.status;
}
var err = new Error(msg);
err.status = xhr.status;
err.method = 'post';
err.url = action;
return err;
}
function getBody(xhr) {
var text = xhr.responseText || xhr.response;
if (!text) {
return text;
}
try {
return JSON.parse(text);
} catch (e) {
return text;
}
}
2. vue封装自己的图片上传组件myUpload.vue:
<template>
<div class="my_upload">
<input
style="display:none"
@change="inputChange"
:multiple="multiple"
type="file"
:name="name"
id="upload"
ref="uploadInput"
/>
</div>
</template>
<script>
import sendRequest from "./axios.js"
export default {
name: "my_upload",
props: {
multiple: {//是否多选
type: Boolean,
default: true
},
name: {//文件名字
type: String,
default: "file"
},
action: { //图片上传路径
type: String,
default: "",
require: true
},
data:{ //图片上传参数
type:Object,
default:()=>({})
},
headers:{ //请求头
type:Object,
default:()=>({})
},
},
methods: {
inputChange(ev) {
const files = ev.target.files;
if (!files) return;
this.uploadFiles(files);
},
uploadFiles(files) {
let postFiles = Array.prototype.slice.call(files); //因为files是具有length属性的对象,Array.prototype.slice.call(arguments)能将具有length属性的对象(key值为数字)转成数组。
//如var obj = {0:'hello',1:'world',length:2};console.log(Array.prototype.slice.call(obj,0));输出为["hello", "world"]
if (!this.multiple) { //非多选情况下,取第一个
postFiles = postFiles.slice(0, 1);
}
if (postFiles.length === 0) { //没有就不在向下执行
return;
}
postFiles.forEach(rawFile => {
this.upload(rawFile);
});
},
upload(rawFile) {
this.$refs.uploadInput.value = null;
if (typeof XMLHttpRequest !== "undefined") {
//这里使用了两种方式,fetch和原生方式,由于fetch不支持获取上传的进度,如果不需要进度条或者自己模拟进度或者XMLHttpRequest对象不存在的时候,使用fetch请求上传逻辑会更简单一些
this.xhrSubmit(rawFile);
} else {
this.fetchSubmit(rawFile);
}
},
xhrSubmit(rawFile) { //ajax请求上传图片
const _this = this;
let option = {
file: rawFile,
data: this.data,
filename: this.name || "file",
action: this.action,
headers:this.headers,
onProgress(e) {
_this.$emit("progress",e)
},
onSuccess(res) {
_this.$emit("success",res)
},
onError(err) {
_this.$emit("error",err)
}
}
let send = async option => {
await sendRequest(option); //这里用了个异步方法,按次序执行this.sendRequest方法,参数为文件列表包装的每个对象,this.sendRequest下面紧接着介绍
};
send(option);
},
fetchSubmit(rawFile) { //fetch上传图片
const _this = this;
let keys = Object.keys(this.data),
values = Object.values(this.data),
action = this.action;
let tempArr=[rawFile];
const promises = tempArr.map(each => {
each.status = "uploading";
let data = new FormData();
data.append(this.name || "file", each);
keys.forEach((one, index) => data.append(one, values[index]));
return fetch(action, {
method: "POST",
headers: {
"Content-Type": "application/x-www-form-urlencoded"
},
body: data
})
.then(res => res.text())
.then(res => JSON.parse(res)); //这里res.text()是根据返回值类型使用的,应该视情况而定
});
Promise.all(promises)
.then(resArray => { //多线程同时开始,如果并发数有限制,可以使用同步的方式一个一个传,这里不再赘述。
resArray.forEach((res, index) => {
_this.$emit("finished",res)
});
})
},
submit() {
this.$nextTick(() => {
this.$refs.uploadInput.click();
});
}
}
};
</script>
<style lang="less" scoped>
</style>
3. 引入组件myUpload.vue并使用:
<template>
<div class="index">
<my-upload
ref='upload'
action="http://xxxxxxxxx:8080/upload"
:data="{token:'ace'}"
@progress='onProgress'
@success='onSuccess'
@error='onError'
@finished='onFinished'
>
</my-upload>
<button class="btn" @click="upload">点击上传</button>
</div>
</template>
<script>
import MyUpload from "@/components/myUpload.vue"
export default {
components:{
MyUpload
},
methods:{
upload(){ //点击上传
this.$nextTick(()=>{
this.$refs.upload.submit();
})
},
onError(err){ //ajax上传失败
console.log(err)
console.log("err")
},
onSuccess(res){ //ajax上传成功
console.log(res)
console.log("success")
},
onProgress(e){ //ajax上传进度
console.log(e)
console.log("progress")
},
onFinished(e){ //fetch请求的上传结果
console.log(e)
console.log("finished")
}
}
}
</script>
最后
以上就是苗条电话为你收集整理的Vue封装基于ajax和fetch两种方式上传文件组件完整代码的全部内容,希望文章能够帮你解决Vue封装基于ajax和fetch两种方式上传文件组件完整代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复