一、前言
在项目中,很多情况下我们都会用到文件上传,但是当某个文件太大,或者不小心选错了文件时,我们就需要终止当前的请求,重新上传文件。同时也能提高网站性能,去除多余请求。
二、代码
现在我们上传文件,很多都会上传到OSS,现在以阿里云的OSS上传为例(仅为前端代码,Vue实例):
uplodaFile组件封装
<template>
<div :class="$style.uploadPack">
<input type="file" @change="$_onUpload" />
<slot />
</div>
</template>
<script>
import { commonService } from '@/common/service' // 封装的接口请求,根据项目情况而定
import axios from 'axios'
export default {
methods: {
async $_onUpload(e) {
this.$emit('input', { status: 'begin', data: null })
const files = e.target.files
let formData = new FormData()
const fileName = files[0].name
/**
getOssToken 返回的数据格式
{
expire: 1607499265904
params: {
signature: "1",
OSSAccessKeyId: "1",
key: "1",
policy: "1",
success_action_status: "200",
x-oss-security-token: "1"
},
url: "http://xxx.aliyuncs.com"
}
*/
const { data } = await commonService.getOssToken({ filename: fileName }) // 获取阿里云oss返回的数据
Object.keys(data.result.params).forEach(key => {
formData.append(key, data.result.params[key])
})
formData.append('file', files[0])
const self = this
try {
/**
* 注意此处接口没有数据返回 只有状态
* 成功后需要自己根据 getOssToken 接口返回的数据组装返回
*/
await axios.post(data.result.url, formData, {
cancelToken: new axios.CancelToken(function executor(c) {
self.source = c
}),
})
/**
* 通过同步数据给父组件
*/
this.$emit('input', { status: 'end', data: { file_name: fileName, url: data.result.url + '/' + data.result.params['key'] } })
/**
* 上传成功后清空表单,避免重名文件不再次执行change事件
*/
e.target.value = ''
} catch (err) {
/**
* 是否是手动终止取消 导致的失败
*/
if (axios.isCancel(err)) {
this.$message.error(err.message)
} else {
this.$message.error('上传失败')
}
this.$emit('input', { status: 'end', data: {} })
e.target.value = ''
}
},
/**
* 终止上传接口请求
*/
cancelRequest() {
if (typeof this.source === 'function') {
this.source('取消文件上传')
}
},
},
}
</script>
<style lang="scss" module>
.uploadPack {
position: relative;
overflow: hidden;
input {
position: absolute;
z-index: 1;
width: 100%;
height: 100%;
opacity: 0;
}
}
</style>
组件使用
<template>
<div>
<uploadPack v-model="packInfo" ref="uploadPack">
<a-button :loading="loading" type="primary">上传</a-button>
</uploadPack>
<a-button @click="cancelRequest"></a-button>
</div>
<template>
<script>
export default {
data() {
return {
loading: false,
fileData: {},
}
},
watch: {
/**
* 监听文件上传的数据变化
*/
packInfo(newValue) {
if (newValue.status === 'begin') {
this.loading = true
} else if (newValue.status === 'end') {
this.loading = false
this.fileData = newValue.data
}
}
},
methods: {
/**
* 终止上传
*/
cancelRequest() {
this.$refs['uploadPack'] && this.$refs['uploadPack'].cancelRequest()
}
}
}
<script>
三、结语
使用场景:
- 页面中新增弹层中有需要上传文件,点关闭弹层按钮时需要终止当前请求。
- 文件上传错误,需要点击取消,重新选择。
- 多次请求时,终止上一次请求,例如搜索框,每输入一个字符都要发送一次请求,但输入过快的时候其实前面的请求并没有必要真的发送出去。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。