Vue Axios文件上传进度条
麦兜小心点 人气:0前文: 之前一直用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(() => {}) }) }
加载全部内容