欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 幼教 > 封装一个vue3的文件上传组件(拖拽或点击选择文件)

封装一个vue3的文件上传组件(拖拽或点击选择文件)

2024/10/25 4:16:53 来源:https://blog.csdn.net/Angel_Tears_/article/details/142535497  浏览:    关键词:封装一个vue3的文件上传组件(拖拽或点击选择文件)

1. 效果

在这里插入图片描述

选择文件后:
在这里插入图片描述

2. 代码

<template><divclass="drop-zone c-normal":class="{borderOutline: outline,}"@dragover.prevent@drop.prevent="handleDrop"@click="chooseFiles"><div v-if="files.length < 1" class="flex items-center justify-center"><slot name="blank"><div class="f-6"><svg-icon icon-class="upload-fill"></svg-icon></div></slot></div><div v-if="files.length < 1"><slot name="title" :is-dragging="isDragging"><div v-if="!isDragging" class="upload-instructions f6">点击或将文件拖到这里上传</div><div v-else class="dragging-feedback">释放以上传文件</div></slot></div><div class="flex items-center"><div v-for="(file, index) in files" :key="index" class="flex file-item pa2 flex-column"><div class="f2 pa2"><svg-icon icon-class="file" /></div><div class="f6 truncate">{{ file.name }}</div><div class="delete-icon" @click.stop="removeFile(index)"><svg-icon icon-class="delete" /></div></div></div><input ref="fileInput" type="file" multiple style="display: none" @change="inputChange" /></div>
</template>
<script lang="ts" setup>
import { computed, ref } from 'vue';
import SvgIcon from '@/components/SvgIcon/SvgIcon.vue';type Prop = {outline?: boolean;maxFiles?: number;data: any;fileChange?: (data: any) => boolean | Promise<boolean>;
};const props = withDefaults(defineProps<Prop>(), {outline: true,maxFiles: -1,data: [],fileChange: () => true,
});const emits = defineEmits(['update:data']);const isDragging = ref(false);
const files = computed({get() {return props.data;},set: async (val) => {const flag = await props.fileChange(val);if (val.length > props.maxFiles){//:TODO 这里需要自定义一哈console.log('最多只能上传'+props.maxFiles+'个文件');return}if (flag === false) {return;}emits('update:data', val);},
});
const fileInput = ref<HTMLInputElement>();const handleDrop = (e: DragEvent) => {isDragging.value = false;const newFiles: File[] | any = e.dataTransfer?.files || [];files.value = [...files.value, ...newFiles];
};const chooseFiles = () => {if (fileInput.value) {fileInput.value.click();}
};const inputChange = (e: Event) => {const target = e.target as HTMLInputElement;const newFiles = target.files || [];files.value = [...files.value, ...newFiles];
};const removeFile = (index: number) => {files.value.splice(index, 1);
};
</script><style lang="scss" scoped>
/*这里的我用的是外部的公共样式, 实际并没有在组件内, 这里将用到的样式复制在下面了*/
:root{--c-normal: #a6a5ad;
}
.flex {display: flex;
}
.items-center {align-items: center;
}
.justify-center {justify-content: center;
}
.c{&-normal{color: var(--c-normal);}
}
.f2 {font-size: 2.25rem;
}
.pa2 {padding: 0.5rem;
}
.f-6,
.f-headline {font-size: 6rem;
}
.truncate {white-space: nowrap;overflow: hidden;text-overflow: ellipsis;
}
/* ↑↑↑ 上面都是引用的公共样式  */
.drop-zone {box-sizing: border-box;width: 100%;height: 100%;padding: 20px;text-align: center;min-height: 150px;overflow-y: auto;&.borderOutline {border: 2px dashed #aaa;}.dragging-feedback {background-color: var(--c-normal);}.upload-instructions {margin-bottom: 10px;}.file-item {position: relative;width: 6rem;.delete-icon {position: absolute;top: 5px;right: 5px;cursor: pointer;color: var(--c-normal);&:hover {color: #1a1a1a;}}}
}
</style>

这个组件引入了 <svg-icon/>这个组件(这里可以替换为自己需要的组件), svg-icon 这个组件的封装可以参考这篇文章: vue3 + vite +ts 封住昂svg-icon组件

这篇文章距离现在时间比较长了, 可能会有一些版本问题, 若遇问题可参考其他相似的文章

如果有什么问题或建议欢迎评论或留言

3. 组件说明

prop参数

name说明默认值
outline外边框true
maxFiles最大文件数(大于-1时生效)-1
data文件数据(双向绑定的)[]
fileChange当文件变化时生效需返回一个boolen或Promise<boolean>类型()=>true

slot

name说明参数
blank文件时显示的图标-
title显示的文字isDragging是否正在拖拽

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com