前文:之前一直用Elemet-UI的upload组件,但是ui给出的样式Element-UI满足不了,所以决定自己写一个玩玩
总体分三步:
页面布局(自定义上传组件样式)Axios上传监听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 } = resif (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 } = econst uploadPrecent = ((loaded / total) * 100) | 0this.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) returnconst formData = new FormData()formData.append('file', file)uplaodFileApi(formData, this.onProcess).then(res => {const { success, msg, data } = resif (success) {this.fileInfo = data}})},onProcess(e) {const { loaded, total } = econst uploadPrecent = ((loaded / total) * 100) | 0this.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(() => {})})}