上传组件封装 - 单独使用接口请求
前期准备工作
-
首先准备好上传接口
请求头一般要把类型改成form-data,还有就是请求头的token了,这里我在axios封装的时候就已经加过了
uploadImg: (data: any) => http.post(`/system/files/upload`, data, { headers: { 'Content-Type': 'multipart/form-data' } }),
-
下面直接上组件封装部分
`
<script lang="ts" setup>
import { ref, watch } from 'vue'
import { Plus, ZoomIn, Delete } from '@element-plus/icons-vue'
import { ElMessage, ElLoading, type UploadProps } from 'element-plus'
import userService from '@/commons/request'
interface Props {
imageUrl?: string // 回显图片地址
action?: string // 上传地址
imgText?: string // 文字可以不传
imgUpText?: string // 上传按钮的文字
disabledType?: boolean // 是否禁用上传
}
const props = withDefaults(defineProps<Props>(), {
imageUrl: '',
action: '/activity/resource/uploadFile',
imgText: '支持jpg/jpeg/png;文件大小不能超过2M;封面图建议尺寸940px*400px',
imgUpText: '上传封面',
disabledType: false,
})
const imagesURL = ref<string>(props.imageUrl)
const emits = defineEmits(['imgSuccess', 'imgDelete'])
const disabled = ref<boolean>(props.imageUrl ? true : false)
const handleChange = (file: any, fileList: any) => {
console.log(file)
console.log(fileList)
let rawFile = file.raw
if (
rawFile.type !== 'image/jpeg' &&
rawFile.type !== 'image/png' &&
rawFile.type !== 'image/jpg'
) {
ElMessage.error('仅支持格式为jpg, jpeg, png的图片')
return false
} else if (rawFile.size / 1024 / 1024 > 2) {
ElMessage.error('图片文件大小不能超过2MB!')
return false
} else {
let formData = new FormData()
formData.append('file', rawFile)
// formData.append('fileType', '1') // 1:图片 2:视频 3:音频 4:文档
const loadingInstance = ElLoading.service({
text: '正在上传',
background: 'rgba(0,0,0,.2)',
})
// 请求接口上传图片到服务器
userService.uploadImg(formData).then((res: any) => {
console.log(res)
if (res) {
loadingInstance.close()
let obj = {
imgUrl: res.url,
}
emits('imgSuccess', obj)
imagesURL.value = res
} else {
loadingInstance.close()
ElMessage.warning(`文件上传失败`)
}
})
}
return true
}
const dialogVisible = ref(false)
const handlePictureCardPreview: UploadProps['onPreview'] = ($event: any) => {
$event.stopPropagation()
dialogVisible.value = true
}
const handlePictureCardDelete: UploadProps['onRemove'] = ($event: any) => {
// 禁止冒泡
$event.stopPropagation()
imagesURL.value = ''
emits('imgDelete', '')
disabled.value = false
return false
}
watch(
() => props.imageUrl,
() => {
imagesURL.value = props.imageUrl
},
)
</script>
<style lang="scss" scoped>
:deep().avatar-uploader {
.avatar {
width: 300px;
height: 204px;
display: block;
}
.el-upload {
border: 1px dashed #dcdfe6;
border-radius: 6px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: 0.2s;
background: rgba(0, 0, 0, 0.04) !important;
}
.el-upload:hover {
border-color: #14b194;
}
}
.el-icon.avatar-uploader-icon {
font-size: 32px;
color: rgba(0, 0, 0, 0.45);
text-align: center;
}
.upImgBox {
width: 300px;
height: 204px;
font-size: 14px;
font-family:
PingFangSC-Regular,
PingFang SC;
font-weight: 400;
color: rgba(0, 0, 0, 0.65);
text-align: center;
padding-top: 24px;
box-sizing: border-box;
}
.up-img-text {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.upImgText {
font-size: 14px;
color: rgba(0, 0, 0, 0.6);
margin-top: 4px;
}
.avatar-img-wrapper {
position: relative;
display: inline-block;
width: 300px;
height: 204px;
border-radius: 6px;
overflow: hidden;
background: rgba(0, 0, 0, 0.04) !important;
}
.icon-group-marker {
position: absolute;
width: 100%;
height: 100%;
left: 0;
top: 0;
cursor: default;
display: inline-flex;
justify-content: center;
align-items: center;
color: #fff;
opacity: 0;
font-size: 20px;
background-color: var(--el-overlay-color-lighter);
transition: opacity var(--el-transition-duration);
}
.icon-group-marker:hover {
opacity: 1;
}
.avatar-preview-icon {
font-size: 32px;
color: rgba(255, 255, 255, 0.85);
cursor: pointer;
}
.avatar-delete-icon {
margin-left: 20px;
font-size: 32px;
color: rgba(255, 255, 255, 0.85);
cursor: pointer;
}
</style>
效果图
上传前
上传后
鼠标滑过
预览