前言
文件上传是必须要掌握的,上传文件这里不说原理了,一般都是把拿到的文件转化为base64或者blob二进制传送给后端,主要用到前端的input标签中type属性中的file。
单文件、多文件上传
因为单文件和多文件上传的原理都是一样的,所以会一个另一个也就会了,这是为了方便使用的是vue外部引用没有使用脚手架
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>多文件上传</title>
</head>
<body>
<div id="app">
<input type="file" name="file" multiple @change="fileChange">
<span v-for="item in fileList">{{item.name}}</span>
<div v-for="item in imgbase64">
<img :src="item" alt="">
</div>
<button @click="onsubmit">提交文件</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
new Vue({
el: '#app',
data: {
fileList: [], //多文件上传存储
imgbase64: [], //多文件转为base64位
},
methods: {
fileChange(e) {
console.log(e.target.files);
//把所有上传的图片文件转化为base64显示在页面上
let file = e.target.files[0]
//创建文件读取对象 异步的
let fr = new FileReader();
let that = this;
//readAsDataURL方法会将获取的文件转化为base-64字符串
fr.readAsDataURL(file)
//监听页面刷新也就是有文件上传了就把这个文件添加到imgbase64数组中
fr.onload = function () {
that.imgbase64.push(fr.result)
}
//多文件上传 判断当前文件的个数是否大于1,如果大于1说明是多文件就让文件数组和自己定义的fileList数组拼接,如果文件数量不大于1就直接把文件添加进去
if (e.target.files.length > 1) {
//这个地方用拼接是因为,我们上传的文件会存在一个对象里面的数组中,图片我放在下面了
this.fileList.concat(e.target.files)
} else {
this.fileList.push(e.target.files[0])
}
},
async onsubmit() {
//因为上传的文件是file类型不能直接发给后端需要用FormData当作载体传送
let that = this;
console.log(that.fileList);
that.fileList.forEach(item => {
let _formData = new FormData()
_formData.append(item.name + 'file', item);
//这里直接发送请求
// axios.post()
});
}
},
})
</script>
</html>
我们可以看到我们上传的文件本获取到以后是一个对象,对象里面有各种属性,我们文件内容就存放在e.target.files这个里面,有很多教程说多文件上传只需要给input设置 一个multiple就可以的,但是这样在选择上传文件的时候如果想选择多个文件需要按住 Ctrl+鼠标点击,如果不这样还是一次只能点击一个,毕竟大多数用户都不懂技术,所以我们要全面考虑。
分割切片上传
这中方式是考虑到文件太大,一次上传需要很长时间造成卡顿,或则我们需要一个进度条来显示文件上传的进度,
思路:把获取到的文件进行转成base64字符串,我们设定一个每次上传的大小,使用slice里面参数设置为自己定义的么欸此上传的大小。请看代码注释写的很清楚
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>切片上传</title>
</head>
<body>
<div id="app">
<input type="file" name="file" multiple @change="fileChange">
<button @click="onsubmit">提交文件</button>
</div>
</body>
<script src="https://cdn.jsdelivr.net/npm/vue@2/dist/vue.js"></script>
<script>
let _fileObject;
new Vue({
el: '#app',
data: {
baifenbi:'',//上传的百分比
},
methods: {
fileChange(e) {
//这个地方是让每次上传的文件按对象都是一个,方便后面使用
_fileObject = e.target.files
},
async onsubmit() {
//大文件进行切割上传
let size=2*1024*1024;//每次上传多少
let fileSize=_fileObject.size;//文件的总大小
let current=0;//上传的大小
localStorage.setItem(_fileObject.name.current);
//这个存储到本地是为了断点续传,上传中断了,记录中断的位置,下次继续上传
while (current<fileSize) {//当上传的大小小于总文件大小就继续上传
//创建一个FormDate对象用来当作载体运输我们的文件传给后端
let _formData=new FormData()
//第一个参数是 上传的文件名字 第二个是每次截取多少文件上传
let sliceFile=_formData.append(_fileObject.name,_fileObject.slice(current,current+size))
//发送请求
await axios.get('请求地址',sliceFi)
//做一个百分进度条
this.baifenbi=Math.min((current/fileSize)*100,100).toFixed(0)
current+=size;
}
}
},
})
</script>
</html>
总结
文件上传很重要,项目中总会遇到文件上传,方法千千万,适合自己最重要