在平時項目開發中,咱們常常會對文件作一些上傳操做,不單單要實現基本需求,也要兼顧用戶體驗,根據本身在工做中遇到的問題談談對圖片上傳的預覽以及上傳進度的優化。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綁定文件改變監聽方法,打印事件參數以下:
發現剛纔選擇的文件在Event>target>files下面
files是一個數組,剛纔只選擇了一張圖片,因此長度爲1,圖片的名稱(name),大小(size),類型(type)都有包含。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的一些介紹:服務器
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>
而後再上傳圖片,以下:
能夠看到,點擊上傳後,頁面出現進度模態框,讓用戶知道已經上傳百分比,優化用戶體驗。