vue3 原生代码封装图片上传组件

151 阅读2分钟

自定义封装图片上传组件并自定上传细节

<template>
	<label
		class="admin-upload-oss"
		:class="{
			'admin-upload-oss-img-true': fileUrl,
		}"
		:form="'uploadID' + uploadID"
	>
		<img
			v-if="fileUrl"
			class="admin-upload-oss-img"
			:src="fileUrl"
			alt="fileUrl"
			@error="handleError"
		/>
		<div v-else class="admin-upload-oss-text" :style="{ color: textColor }">
			<el-icon><Plus /></el-icon>
			<div class="up-text">点击上传</div>
			<div class="triangle-up"></div>
		</div>
		<input
			:id="'uploadID' + uploadID"
			ref="uploadInput"
			accept="image/png, image/jpeg, image/jpg"
			class="hidden"
			type="file"
			@change="handleUpload"
		/>
	</label>
</template>
<script setup lang="ts">
import { fetchUploadFile } from '~/fetch/http'
import loginIcon from '@/assets/img/login/login-icon1.png'
import { ElMessage } from 'element-plus'
import { Plus } from '@element-plus/icons-vue'

defineProps({
	textColor: {
		type: String,
		default: '#2267c5',
	},
})

// uploadID
const uploadID = (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1)
// 上传状态
const loading = ref(false)
// 上传对象
const uploadInput = ref()
// 图片url
const fileUrl = defineModel('fileUrl', {
	type: String,
	default: '',
})
// 上传
const handleUpload = async (fileData: any) => {
	try {
		const file = fileData.target.files[0]
		if (!file) {
			return false
		}
		// 限制的格式范围
		const txtName = '.jpg|.png|.jpeg'
		// 校验-把路径中的所有字母全部转换为小写
		const extName = file.name
			.substring(file.name.lastIndexOf('.'))
			.toLowerCase()
		const extSize = file.size
		// 判断格式
		if (!txtName.includes(extName)) {
			ElMessage({
				message: '请上传正确的文件格式!如:' + txtName,
				type: 'error',
			})
			uploadInput.value.value = null
			return false
		}
		// 判断大小
		if (extSize / 1000 / 1000 > 3) {
			ElMessage({
				message: '请上传小于 3M 的图片!',
				type: 'error',
			})
			uploadInput.value.value = null
			return false
		}
		if (!file) return false
		// 开始上传
		loading.value = true
		ElMessage({
			message: '上传中',
			type: 'success',
		})
                
          // 根据接口要求封装
		const formData = new FormData()
		formData.append('bucket', 'BS')
		formData.append('path', '/bs')
		formData.append('type', 'image')
		formData.append('importFile', file)
		const { data } = await fetchUploadFile(formData)
		ElMessage({
			message: '上传成功',
			type: 'success',
		})
		fileUrl.value = data.accessUrl
		loading.value = false
	} catch (error: any) {
		ElMessage({
			message: error.data?.msg || '上传失败',
			type: 'error',
		})
		uploadInput.value.value = null
		loading.value = false
	}
}

// 监听 visible 清空 fileUrl
// watch(
// 	() => props.visible,
// 	() => {
// 		fileUrl.value = ''
// 	},
// )

const handleError = (event: any) => {
	event.target.src = loginIcon
}
</script>
<style lang="scss">
// 上传头像 做上传图片展示限制以及上传失败结果处理显示
.admin-upload-oss {
	display: block;
	width: 177px;
	height: 210px;
	background: #ddf8f1;
	border-radius: 6px;
	border: 1px solid #c5e1d9;
	position: relative;
	cursor: pointer;

	.admin-upload-oss-text {
		position: relative;
		color: #666666 !important;


		.triangle-up {
			position: absolute;
			width: 0;
			height: 0;
			bottom: -20px;
			z-index: 1;
			border-left: 88px solid transparent;
			border-right: 88px solid transparent;
			border-bottom: 100px solid rgb(255, 255, 255); /* 颜色 */
		}

		.up-text {
			position: absolute;
			z-index: 2;
			bottom: 30px;
			left: 60px;
      color: #15c298;
		}

		.el-icon {
			font-size: 46px;
			color: #15c298;
			font-weight: 600;
			position: absolute;
			bottom: 85px;
      left: 65px;
		}
	}

	&:hover {
		.admin-upload-oss-text {
			opacity: 0.6;
		}
	}
	&.admin-upload-oss-img-true {
		&::before {
			position: absolute;
			content: '重新上传';
			bottom: 10px;
			left: 0;
			width: 100%;
			height: 30px;
			z-index: 2;
			text-align: center;
			color: rgba(255, 255, 255, 0.6);
			transition: all 0.3s;
			opacity: 0;
		}
		&:hover {
			&::before {
				opacity: 1;
			}
			.admin-upload-oss-img {
				opacity: 0.6;
			}
		}
	}

	// 提示问题
	.admin-upload-oss-text {
		position: absolute;
		bottom: 21px;
		width: 100%;
		text-align: center;
		transition: all 0.3s;
	}
	// 展示 img
	.admin-upload-oss-img {
		display: block;
		width: 100%;
		height: 100%;
		object-fit: cover;
		border-radius: 6px;
		position: relative;
		transition: all 0.3s;
	}

	.hidden {
		visibility: hidden;
	}
}
</style>