在平时项目开发中,咱们常常会对文件作一些上传操做,不单单要实现基本需求,也要兼顾用户体验,根据本身在工做中遇到的问题谈谈对图片上传的预览以及上传进度的优化。javascript
基于Vue.js+axios搭建的项目,新建一个Index.Vue项目以下,基本结构能够先能够选择文件,预览文件。html
<template>
<div class="wrapper">
<h2 class="text-center">上传图片</h2>
选择文件:<input type="file" multiple="true" accept="image/gif, image/jpeg" @change="handleFileChange($event)">
<p>图片预览:</p>
<img v-show="imgPreViewSrc" :src="imgPreViewSrc" alt="图片预览">
<button v-show="file" @click="uploadFile">上传文件到服务器</button>
</div>
</template>
<script> ... data(){ return{ imgPreViewSrc:'', //文件预览地址 file:null, //上传文件 } } methods:{ } ... </script>
<style lang="less" scoped> .text-center{ text-align: center; } .wrapper{ font-size: 16px; width: 60%; height: 100%; margin: 0 20%; border: 1px solid #ddd; img{ width: 200px; } button{ width:120px; height: 30px; margin-top: 30px; line-height: 30px; border: 1px solid #CCC; text-align: center; } } </style>
复制代码
input的类型type设置为file,能够选择文件,multipe属性设置为true,一次能够选择多个文件。 运行项目,页面以下: vue
选择一个图片文件(bg.jpg),以前有在input绑定文件改变监听方法,打印事件参数以下: java
2.1.设置文件类型 在input标签accept属性设置文件类型,当用户打开文件资源管理器选择文件时,会过滤掉其余类型文件,可以从源头避免用户选择脏文件,也更加方便用户选择文件。ios
<input type="file" multiple="true" accept="image/gif, image/jpeg" @change="handleFileChange($event)">
复制代码
2.2.图片预览 要将用户选择的文件显示到页面上,以方便用户下一步操做,由于用户可能会从选择的文件中再挑选几张图片操做,例如上传到服务器。 图片预览要用到URL对象的URL.createObjectURL(file)方法生成一个blob地址,直接赋值给img标签的src,页面就能够展现。(URL.createObjectURL() 静态方法会建立一个 DOMString,其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和建立它的窗口中的 document 绑定。这个新的URL 对象表示指定的 File 对象或 Blob 对象。) 在methods添加handleFileChange方法,预览图片web
...
// 文件改变监听事件
handleFileChange(evt){
console.log(evt);
let file=evt.target.files[0];
this.file=file;
let src=URL.createObjectURL(file);
this.imgPreViewSrc=src;
},
...
复制代码
预览以下: axios
选择好文件以后,文件要上传到服务器,有时候文件很大或者网速很慢的状况下,用户须要知道已经上传进度,若是没有上传进度,用户退出页面那么文件就上传失败了。api
3.1.修改script文件数组
<script>
import axios from 'axios';
// 文件上传服务api
const baseURL='http://127.0.0.1/api';
function upload (params,cb=null) {
return new Promise((resolve, reject) => {
axios.create({
baseURL,
})({
url:'/upload/uploadFile/image',
method:'post',
data:params,
// 上传进度
onUploadProgress:function(progressEvent){
if(progressEvent.lengthComputable && cb){
cb(progressEvent);
}
},
}).then(res => {
console.log(res.data);
if(res.status===200){
resolve(res.data);
}else{
reject(res.data);
}
}).catch(err => {
reject(err);
});
});
}
...
// 上传文件到服务器
uploadFile(){
let file=this.file;
if(file){
let formData = new FormData();
formData.append('file', file);
upload(formData,(progressEvent)=>{
console.log(progressEvent);
});
}else{
alert('请选择文件')
}
...
</script>
复制代码
3.2.上传进度 在axios入参新增onUploadProgress方法,在文件上传过程当中该方法会调用,参数包含上传的一些信息。 有关ProgressEvent的一些介绍:bash
ProgressEvent 是一个用来测量底层操做进度的接口,能够测量HTTP请求(例如:一个 XMLHttpRequest请求、或者一个底层资源如img,audio,video等,ProgressEvent经常使用属性值: ProgressEvent.lengthComputable:它是一个布尔值标识,代表总共须要完成的工做量和已经完成的工做是否能够被底层所计算到。换而言之,它表示的就是过程是不是能够测量的。 ProgressEvent.loaded:是一个unsigned long long类型,表示底层进程已经执行的工做量。所作的工做比率能够用属性和ProgressEvent.total计算。当使用HTTP下载资源时,这只表示内容自己的一部分,而不是头和其余开销。 ProgressEvent.total:是unsigned long long类型,表示底层进程正在执行的工做总量。当使用HTTP下载资源时,这只表示内容自己,而不是头和其余开销。
点击上传按钮,打开控制台:
能够发现ProgressEvent中loaded属性值为图片文件上传的大小,total为文件的大小。
3.3.在页面添加进度条 为了组件通用化,新建一个Progress.vue组件,接受一个progressValue进度参数。
<template>
<div class="progress-box">
<div class="progress-content">
<p v-if="progressValue<100">上传进度:{{progressValue}}%</p>
<p v-else>上传成功!</p>
<progress :value="progressValue" max="100"></progress>
</div>
</div>
</template>
<script>
export default {
props:['progressValue'],
name: 'Progress',
};
</script>
<style lang="less" scoped>
.progress-box{
position: fixed;
top:0;
left:0;
bottom: 0;
right:0;
background: rgba(0,0,0,0.5);
.progress-content{
position: absolute;
top:50%;
left:50%;
width: 300px;
height: 76px;
padding: 8px 30px;
transform: translate(-150px,-38px);
background: #fff;
border-radius: 8px;
p{
margin-bottom: 5px;
}
progress{
width: 100%;
height: 22px;
}
progress::-webkit-progress-bar{
background-color:#d7d7d7;
}
progress::-webkit-progress-value{
background-color:orange;
}
}
}
</style>
复制代码
在div末尾添加Progress组件,再修改Index.vue文件methods的上传方法:
<template>
<div class="wrapper">
...
<Progress :progressValue="progressValue" v-if="isShowProgressBox"></Progress>
</div>
</template>
<script>
import Progress from '../components/Progress';
...
// 上传文件到服务器
uploadFile(){
let file=this.file;
if(file){
let formData = new FormData();
formData.append('file', file);
upload(formData,(progressEvent)=>{
this.isShowProgressBox=true;
this.progressValue=parseFloat((progressEvent.loaded/progressEvent.total*100).toFixed(2));
if(this.progressValue===100){
let timer=setTimeout(()=>{
this.isShowProgressBox=false;
clearTimeout(timer);
timer=null;
},500);
}
});
}else{
alert('请选择文件');
}
...
</script>
复制代码
而后再上传图片,以下:
能够看到,点击上传后,页面出现进度模态框,让用户知道已经上传百分比,优化用户体验。