持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第5天,点击查看活动详情
对 element plus的el-upload的二次封装
没什么难的,感觉分开说的话也没什么,就直接贴出整体代码啦,注释应该是比较详细的,特别注意点的话,就在下面解释,有耐心的话可以看看
<template>
<div>
<!-- 图片上传组件 :on-change='picChange' :http-request="upload"-->
<el-upload
:class="{ hide: isShowUpload }"
:disabled="disabled"
:limit="limits"
:action="uploadUrl"
list-type="picture-card"
v-model:file-list="imgs"
:on-success="handleAvatarSuccess"
:on-preview="watchPic"
:on-error="imgUploadError"
:on-remove="picRemove"
:on-exceed="picExceed"
:before-upload="beforeUpload"
:data="upLoadData"
name="image"
>
<!-- :class="{ hide: isShowUploadPic }" -->
<div class="icon">
<el-icon><CameraFilled /></el-icon>
上传图片
</div>
</el-upload>
<!-- 图片展示的弹层 -->
<el-dialog v-model="showDialog">
<el-image :src="dialogImageUrl" fit="cover" />
</el-dialog>
</div>
</template>
<script setup name="imgUpload">
import { ref, onMounted } from 'vue'
import { ElMessage } from 'element-plus'
import { CameraFilled } from '@element-plus/icons-vue'
const isShowUpload = ref(false)
// props
const props = defineProps({
// 图片开始默认的值
imgs: {
type: Array,
default: () => []
},
// 上传类型
imgType: {
type: Array,
default: () => [
'image/jpeg',
'image/jpg',
'image/png',
'image/gif',
'image/bmp'
]
},
// 上传大小
maxSize: {
type: Number,
// 2 * 1024 * 1024 2M
default: 2097152
},
// 是否禁用
disabled: {
type: Boolean,
default: false
},
// 最大上传数量
limits: {
type: Number,
default: 1
},
// 上传的url
uploadUrl: {
type: String,
default:
import.meta.env.VITE_NODE_ENV === 'development'
? 'https://zyjy-dev.51jshl.com/api/common/upload'
: '/api/common/upload'
},
// 上传时附带的额外参数
upLoadData: {
type: Object,
default: function () {
return { category: 'school_image' }
}
}
})
// emits
const emits = defineEmits(['ossImgUrl'])
// 编辑时 无法修改 props 的imgs,这样进行改变,本来使用 v-model 的,但有点别的原因不这么做啦
let imgList = props.imgs
// 控制显示弹层
let showDialog = ref(false)
// 弹层展示的 预览图片
let dialogImageUrl = ref()
// 展示图片的文件
const watchPic = (file) => {
showDialog.value = true
dialogImageUrl.value = file.url
}
// 移除文件列表 文件列表移除文件时的钩子
const picRemove = (file, filelist) => {
imgList = filelist
isShowUpload.value = imgList.length >= props.limits
}
// 图片上传成功
const handleAvatarSuccess = async (res, file) => {
if (res.code === 200) {
imgList.push({ url: res.data })
emits('ossImgUrl', imgList)
isShowUpload.value = imgList.length >= props.limits
}
}
// 图片上传失败
const imgUploadError = (err, file, fileList) => {
ElMessage.error('图片上传失败')
return false
}
// 当超出限制时,执行的钩子函数
const picExceed = (file, fileList) => {
ElMessage.error(`上传图片最大数量为${props.limits}`)
}
// 文件状态改变时的钩子,添加文件、上传成功和上传失败时都会被调用 这里只是使用超过最大上传数量,隐藏上传组件
// function picChange(file, fileList) {
// isShowUpload.value = fileList.length >= props.limits
// console.log(isShowUpload.value)
// }
// 上传文件之前进行限制 例如文件类型和大小
function beforeUpload(file) {
// console.log(file)
// console.log(props.imgType.includes(file.type))
if (!props.imgType.includes(file.type)) {
ElMessage.error('上传的图片类型只能是JPG、PNG、JPEG的类型')
return false
}
if (file.size > props.maxSize) {
// console.log(file.size)
ElMessage.error('最大上传大小是2M')
return false
}
return true
}
// let ossConfigure = reactive()
// onMounted
onMounted(async () => {
// 编辑时一进来就判断一下是否显示上传
isShowUpload.value = props.imgs.length >= props.limits
})
// 覆盖默认的上传行为
async function upload(params) {
// console.log(params, '覆盖默认的上传行为')
// 这里我本来要这样写的,后面没有,可以不用这个
}
</script>
<style scoped lang="scss">
// 这里的为了超出限制的上传数量,也就是limits的话,隐藏上传显示
::v-deep .hide {
.el-upload--picture-card {
display: none;
transition: 0.3s;
}
}
.icon {
display: flex;
flex-direction: column;
justify-content: center;
text-align: center;
align-items: center;
color: #999;
}
</style>
on-preview: 点击文件列表中已上传的文件时的钩子 =》 点击显示大图on-remove: 文件列表移除文件时的钩子 =》 更新当前的图片on-success: 文件上传成功时的钩子 =》通过 emits 改变父组件绑定的值on-error: 文件上传失败时的钩 =》 提示一下on-exceed: 当超出限制时,执行的钩子函数before-upload: 上传文件之前的钩子,参数为上传的文件, 若返回false或者返回Promise且被 reject,则停止上传。=> 上传之间判断一下上传文件类型,大小,长宽等进行一下限制
给el-upload添加css,根据当前上传张数动态使其显示
1. 首先el-upload里面绑定一个占位class:
<el-upload :on-remove="picRemove" :on-change="picChange" :class="{hide:isShowUpload}" />
2. isShowUpload 的初始值:
const isShowUpload = ref(false)
3.onMounted里面(vue的生命周期,因为编辑的话会触发,我在外面也写了一个,看代码里面的注释):
isShowUpload.value = fileList.length >= props.limits
4. handleRemove里面(删除文件被调用的那个):
fileList = filelist
isShowUpload.value = fileList.length >= props.limits
5. 在style里面加上
<style scoped lang="scss">
::v-deep .hide {
.el-upload--picture-card {
display: none;
transition: 0.5s;
}
}
</style>