最近公司需要有一个拖拽上传的功能,但是由于在开发前,使用的组件库内没有拖拽上传的例子,所以我在这里写一个拖拽上传的功能😁.

首先写一个组件(拖拽上传的组件)

1. 这里上传成功后的提示用的是primevue组件库,可以不用管

2. 目前这里只是单文件上传,如果有需求可以自行更改

3. 这里有用到Bootstrap5的class,所以html部分的样式需要自己更改

4. 目前这边就是按钮上传以及拖拽上传

<template>
	<div v-if="type === 0">
		<a @click="handleClickUpload" class="btn btn-primary">{{buttonText}}</a>
		<input @change="handleUpload" :multiple="isMultiple" ref="uploadRef" type="file" class="d-none" />
	</div>
	<div v-else-if="type === 1" :style="{'width': width, 'height': height}" class="upload-component position-relative">
		<div class="h-100 w-100 position-absolute z-index-1">
			<input @change="handleUpload" :multiple="isMultiple" type="file" />
		</div>
		<img v-if="uploadImageUrl" :src="uploadImageUrl" alt="..." class="w-100 h-100 position-absolute top-0" style="object-fit: cover;" />
		<div v-else class="upload-tips">{{uploadTips}}</div>
	</div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, watchEffect, ref } from 'vue';
import { useToast } from "primevue/usetoast";

export default defineComponent({
	name: "upload-component",
	props: {
		// 组件的类型 - 0: 按钮  1: 拖拽
		type: {
			type: Number,
			default: 0,
		},
		// 上传类型 - 0: 图片  补充...
		uploadType: {
			type: Number,
			default: 0,
		},
		// 是否支持上传多个
		isMultiple: {
			type: Boolean,
			default: false,
		},
		// 图片路径(上传成功后回显 - 仅单张图片) - 拖拽类型生效
		uploadImageUrl: {
			type: String,
			default: "",
		},
		// 宽度 - 拖拽类型生效
		width: {
			type: String,
			default: "200px",
		},
		// 高度 - 拖拽类型生效
		height: {
			type: String,
			default: "200px",
		},
		// 上传的文字提示
		uploadTips: {
			type: String,
			default: "将图片拖放到此处或点击上传",
		},
		// 上传按钮的文字
		buttonText: {
			type: String,
			default: "点击上传",
		},
	},
	setup(props, { emit }) {
		const toast = useToast();
		const uploadRef = ref();
		const state = reactive({
			// 组件的类型
			type: props.type,
			// 允许上传的类型
			uploadType: props.uploadType,
			// 是否支持上传多个
			isMultiple: props.isMultiple,
			// 图片路径(上传成功后回显 - 仅单张图片)
			uploadImageUrl: props.uploadImageUrl,
			// 上传的文字提示
			uploadTips: props.uploadTips,
			// 宽度
			width: props.width,
			// 高度
			height: props.height,
			// 上传的地址
            uploadFileUrl: "这边是上传的路径地址",
		});

		/** 监听... */
		watchEffect(() => {
			state.type = props.type;
			state.uploadType = props.uploadType;
			state.uploadImageUrl = props.uploadImageUrl;
			state.isMultiple = props.isMultiple;
		});

		/** 处理点击上传 */
		const handleClickUpload = () => {
			uploadRef.value.click();
		}

		/** 处理上传之前的钩子 */
		const handleBeforeUpload = (files: any) => {
			let result = true;
			// 判断上传类型
			for(const item of files) {
				if(state.uploadType === 0 && !item.type.includes("image")) {
					result = false;
					break;
				}
			}

			if(!result) {
				toast.add({severity: 'warn', summary: '提示', detail: '当前上传的文件类型不支持', life: 1500});
				return result;
			}
			return result;
		}

		/** 处理上传成功后 */
		const handleAfterUpload = (files: any) => {
			// 目前只是单个上传 - 多个上传以后需求用到再改
			let file = null as any;
			if(!state.isMultiple) {
				file = files[0];
			}
			else {
				file = files[0];
			}

			// 将file文件设置成form数据
			const fileForm = new FormData();
			fileForm.append("file", file);

			// 创建XMLHttpRequest对象
			const xhr = new XMLHttpRequest();
			// 设置请求方式以及路径
			xhr.open("POST", state.uploadFileUrl);
			// 发送请求
			xhr.send(fileForm);
			// 监听请求的结果
			xhr.addEventListener("load", () => {
				const response = JSON.parse(xhr.response);
				toast.add({severity: 'success', summary: '提示', detail: '上传成功', life: 1500});
				emit("handleUploadSuccess", response);
			});
		}

		/** 处理上传操作 */
		const handleUpload = (event: any) => {
			// 上传之前
			if(!handleBeforeUpload(event.target.files)) {
				return;
			}

			// 上传后
			handleAfterUpload(event.target.files);
		}

		return {
			...toRefs(state),
			uploadRef,
			handleUpload,
			handleBeforeUpload,
			handleClickUpload,
		}
	}
});
</script>

<style scoped lang="scss">
	.upload-component {
		width: 400px;
		height: 400px;
		border-radius: 4px;
		border: 1px dashed #d9d9d9;
		background: #f5f5f5;
		cursor: pointer;
		position: relative;
		overflow: hidden;
		&:hover {
			transition: .2s;
			border-color: #409eff;
		}

		.upload-tips {
			font-size: 12px;
			color: #999;
			line-height: 20px;
			position: absolute;
			top: 50%;
			left: 50%;
			transform: translate(-50%, -50%);
            text-align: center;
			width: 70%;
		}

		input {
			cursor: pointer;
			width: 100%;
			height: 100%;
			position: absolute;
			left: 0;
			padding-bottom: 30px;
			transform: translateY(-30px);
			box-sizing: content-box;
		}
	}
</style>

最后就是引入组件使用就好,组件引入很简单这里就不展示代码,效果图是:

Logo

前往低代码交流专区

更多推荐