Vue+Axios實現文件上傳自定義進度條
前文: 之前一直用Elemet-UI的upload組件,但是ui給出的樣式Element-UI滿足不瞭,所以決定自己寫一個玩玩
總體分三步:
1、頁面佈局(自定義上傳組件樣式)
2、Axios上傳
3、監聽Process 聯動頁面實現進度條
成果
1、頁面佈局
<div class="display-upload-wrapper"> <div class="innier-upload-wrapper" :style="innerUploadStyle"> 自定義的upload樣式 <div v-if="fileInfo">{{ fileInfo.name }}.{{ fileInfo.format }} 上傳完成</div> </div> </div> <input id="upload-file" ref="uploadInput" type="file" @change="getFile">
通過input file 上傳文件 ,原生的upload input 太醜瞭,好多人是不是都忘接瞭什麼樣子瞭,我幫大傢回憶一下
我們可以通過css隱藏這個文件,讓後用js 給其他的dom綁定上這個input的點擊事件實現
CSS
.display-upload-wrapper { border: 1px solid red; width: 384px; height: 54px; cursor: pointer; width: 244px; border-radius: 4px; background: #F4F8FF; .innier-upload-wrapper { height: 100%; background: linear-gradient(270deg, #C0D8FF 0%, #E7F2FF 100%); background-repeat: no-repeat; background-size: 10% 100%; transition: background-size .3s linear; } } #upload-file { display: none; }
js
document.querySelector('.display-upload-wrapper').onclick = function() { document.querySelector('#upload-file').click() }
這樣點擊就可以調起文件選擇
2、Axios上傳
獲取到選中的文件
getFile() { const file = this.$refs.uploadInput.files[0] if (!file) return // 獲取到的file用FormData處理成表單鍵值對 const formData = new FormData() formData.append('file', file) //uplaodFileApi是文件上傳的api 第一個入參為上傳的文件,第二個入參為上傳的進度的回調 uplaodFileApi(formData, this.onProcess).then(res => { console.log('uplaodFileApi succ: ', res) const { success, msg, data } = res if (success) { this.fileInfo = data } }) },
獲取到的file用FormData處理成表單鍵值對
const formData = new FormData()
formData.append('file', file)Axios的入參為
{ "method":"POST", "url":"/jz/boss/public/upload/b", "data":{ }, "params":{ "appToken":"xxxxxxxxxxxxxxxxxxxxx =" }, "withCredentials":true, "headers":{ "Content-Type":"multipart/form-data;charset=UTF-8" }, "responseType":"" }
data的值就是傳入的fromData,控制臺直接打印不出的
要註意的是 headers的Content-Type 要設置成multipart/form-data;charset=UTF-8 "
Content-Type":"multipart/form-data;charset=UTF-8"
做完這些操作我們就可以上傳成功瞭
3、監聽Process 聯動頁面實現進度條
Axios提供瞭onUploadProgress的回調
所有原生的processs的處理都可以,下面的圖就是這個回調的progressEvent
用total 和loaded我們就可以算出進度條的百分比
onProcess(e) { const { loaded, total } = e const uploadPrecent = ((loaded / total) * 100) | 0 this.uploadPrecent = uploadPrecent },
完整代碼
<template> <div> {{ uploadPrecent }}% <div class="display-upload-wrapper"> <div class="innier-upload-wrapper" :style="innerUploadStyle"> 自定義的upload樣式 <div v-if="fileInfo">{{ fileInfo.name }}.{{ fileInfo.format }} 上傳完成</div> </div> </div> <input id="upload-file" ref="uploadInput" type="file" @click="clearPreUpload" @change="getFile"> </div> </template> <script> import { uplaodFileApi } from '@/api/uploadApi' import { UploadStatus } from './format' export default { name: 'Myupload', data() { return { uplaodStatus: UploadStatus.wait, uploadPrecent: 0, timer: undefined, fileInfo: undefined } }, computed: { innerUploadStyle() { return `background-size: ${this.uploadPrecent}% 100%;` } }, mounted() { this.bindUplaodClickToDisplayUplaod() }, methods: { bindUplaodClickToDisplayUplaod() { document.querySelector('.display-upload-wrapper').onclick = function() { document.querySelector('#upload-file').click() } }, getFile() { const file = this.$refs.uploadInput.files[0] if (!file) return const formData = new FormData() formData.append('file', file) uplaodFileApi(formData, this.onProcess).then(res => { const { success, msg, data } = res if (success) { this.fileInfo = data } }) }, onProcess(e) { const { loaded, total } = e const uploadPrecent = ((loaded / total) * 100) | 0 this.uploadPrecent = uploadPrecent }, clearPreUpload() { } } } </script> <style lang="scss" scoped> .display-upload-wrapper { border: 1px solid red; width: 384px; height: 54px; cursor: pointer; width: 244px; border-radius: 4px; background: #F4F8FF; .innier-upload-wrapper { height: 100%; background: linear-gradient(270deg, #C0D8FF 0%, #E7F2FF 100%); background-repeat: no-repeat; background-size: 10% 100%; transition: background-size .3s linear; } } #upload-file { display: none; } </style>
這個請求代碼刪減過 僅供參考可以理解為 偽代碼
const HttpRequest = (type, option) => { const options = { expirys: true, ...option } return new Promise((resolve, reject) => { const queryParams = { method: type, url: options.url, data: options.data, params: { appToken: requestToken() }, withCredentials: true, headers: options.header ? options.header : DEFAULT_HEADER, responseType: options.responseType || '' } // 如果有onProcess就給axios綁定onUploadProgress回調 if (options.onProcess) { queryParams.onUploadProgress = options.onProcess } if (options.timeout) { queryParams.timeout = options.timeout } axios(queryParams) .then( res => { const { data = {}, headers = {} } = res || {} const result = Object.assign(data, headers) resolve(result) }, err => { reject(err) } ) .catch(error => { reject(error) }) .finally(() => {}) }) }
以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。
推薦閱讀:
- vue封裝el-upload批量上傳隻請求一次接口
- 解析element-ui中upload組件傳遞文件及其他參數的問題
- Vue使用axios圖片上傳遇到的問題
- JavaScript實現監控上傳和下載進度
- 利用node+koa+axios實現圖片上傳和回顯功能