AntDesign上传组件upload二次封装+全局上传hook使用

文章目录

  • 前言
  • a-upload组件二次封装
    • 1. 功能分析
    • 2. 代码+详细注释
    • 3. 使用到的全局上传hook代码
    • 4. 使用方式
    • 5. 效果展示
  • 总结


前言

在项目中,ant-design是我们常用的UI库之一,今天就来二次封装常用的组件a-upload批量上传组件,让它用起来更方便。

a-upload组件二次封装

1. 功能分析

(1)自定义展示区,可按UI规范自定义展示
(2)上传失败,过滤成功的文件,重新赋值展示,不展示失败的文件
(3)上传之前的校验通过配置,在组件内统一管理
(4)通过传入defaultValue prop,进行初始化数据显示
(5)通过传入beforeChange prop,可以根据外部promise上传文件返回的结果,做一些处理

2. 代码+详细注释

// @/components/uploads/index.tsx
<template><a-upload v-model:file-list="state.fileList" :accept="accept" list-type="picture" class="avatar-uploader" multiple :max-count="3" :before-upload="beforeUpload" :customRequest="handlerUploadFile" @change="handlerChange" @remove="handlerRemove"><a-button><UploadOutlined />选择附件</a-button><template #itemRender="{ file, actions }"><div class="cd-upload-list"><LoadingOutlined class="cd-upload-list-loading" v-if="file.status === 'uploading'" /><template v-else><a class="cd-upload-list-item" :href="file?.response || file?.url" target="_blank"><img v-if="isImage(file?.response)" class="cd-upload-list-img" :src="file?.response || file?.url" alt="" /><FileOutlined v-else class="cd-upload-list-icon" /><span class="cd-upload-list-name">{{ file.name }}</span></a></template><a class="cd-upload-list-remove" href="javascript:;" @click="actions.remove"> <DeleteOutlined /></a></div></template></a-upload>
</template>
<script lang="ts" setup>
import { reactive, ref, Ref, watch, PropType } from "vue";
import { message } from "ant-design-vue";
import { UploadOutlined, DeleteOutlined, FileOutlined, LoadingOutlined } from "@ant-design/icons-vue";
import type { UploadProps, UploadChangeParam } from "ant-design-vue";
import type { UploadRequestOption } from "ant-design-vue/es/vc-upload/interface";
/*** 类型声明*/
type ProgressProps = UploadProps["progress"];
type uploadFunProps<T> = Omit<UploadRequestOption<T>, "onSuccess"> &Omit<UploadRequestOption<T>, "onError"> & {onSuccess: any;onError: any;};
/*** @param data 文件地址* 是否是图片*/
const isImage = (data: string | undefined) => {if (!data) return false;const fileExtensions = [".png", ".jpg", ".jpeg"];return fileExtensions.some((extension) => data.endsWith(extension));
};
/*** props*/
const props = defineProps({val: {type: Array,default: () => [],},accept: {type: String,default: ".doc,.docx,.xlsx,.xls,.pdf,.jpg,.png,.jpeg",},max: {type: Number,default: 1,},size: {type: Number,default: 2,},defaultValue: {type: Array,default: () => [],},format: Function,text: {type: String,default: "",},params: {type: Object,default: {},},beforeChange: {type: Function as PropType<(options: any) => Promise<any>>,},
});
/*** emit*/
const emit = defineEmits(["update:val", "upload", "remove"]);
/*** state*/
type PreviewState = {fileList: UploadProps["fileList"];loading: boolean;imageUrl: string;dataList: any[];
};
const state = reactive<PreviewState>({fileList: [],loading: false,imageUrl: "",// 数据文件dataList: [],
});
/*** 文件状态改变时的回调*/
const handlerChange = ({ file, fileList }: UploadChangeParam) => {const status = file.status;if (status === "uploading") {}if (status === "done") {}// 上传失败,过滤成功的文件,重新赋值展示if (!status || status === "error") {const files = fileList.filter((item: any) => item.status === "done");state.fileList = files;}
};
/*** 上传之前检查文件* @param file 文件对象* @returns boolean*/
const beforeUpload = (file: File) => {const type = file.type.split("/")[1];if (props.accept.indexOf(type) === -1) {message.error(`请上传${props.accept}格式文件`);return false;}const maxSize = file.size / 1024 / 1024 < props.size;if (!maxSize) {message.error(`图片大小须小于${props.size}MB`);return false;}return type && maxSize;
};
/*** 上传进度* @param progressEvent 进度对象*/
const progress: ProgressProps = {};
/*** 上传*/
const handlerUploadFile = (options: uploadFunProps<unknown>) => {props?.beforeChange &&props.beforeChange({ file: options.file, params: props.params }).then((res: any) => {message.success(`上传成功`);console.log("res777", res);if (res?.url) {options.onSuccess(res.url, options.file);}}).catch(() => {message.error(`上传失败`);options.onError();});
};
/*** 删除文件的回调* @param file 文件对象*/
const handlerRemove = (file: File) => {emit("remove", file);
};/*** 初始值*/
const initValue = (list: string[]) => {const file = [] as any[];list.forEach((item: string) => {file.push({status: "done",url: item,});});// 更新state.fileList = file;
};
watch(() => props.defaultValue,(val: any) => {if (!val || (val && !val.length)) {return false;}initValue(val);},{ immediate: true }
);
</script>
<style lang="scss" scoped>
.cd-upload-list {display: flex;justify-content: space-between;position: relative;height: 66px;padding: 8px;border: 1px solid #d9d9d9;border-radius: 8px;margin-top: 8px;.cd-upload-list-loading {font-size: 20px;}.cd-upload-list-item {display: flex;align-items: center;.cd-upload-list-img {width: 50px;height: 50px;margin-right: 10px;}.cd-upload-list-icon {font-size: 20px;margin-right: 10px;}.cd-upload-list-name {}}.cd-upload-list-remove {display: flex;align-items: center;font-size: 20px;}
}
</style>

3. 使用到的全局上传hook代码

/*** api*/
import { uploadImage } from "@/api/index";
/*** 上传资源全局hook* @returns */
export function useUploadImage() {const useUploadImageBeforeChange = ({ file, params }: { file: File; params: Record<string, any> }) => {return new Promise((resolve, reject) => {// 实例化表单对象const form = new FormData();// 表单添加 files 字段for (let key in params) {form.append(key, params[key]);}form.append("multipartFiles", file);uploadImage(form).then((res: any) => {const result = res && res.length;resolve(result ? res[0] : null);}).catch(() => {reject();});});};return {useUploadImageBeforeChange,};
}

4. 使用方式

// 引入组件,以及全局上传hook
import Upload from "@/components/upload/index.vue";
import { useUploadImage } from "@/hook/index";
const { useUploadImageBeforeChange } = useUploadImage();
// 使用
const defaultValue: string[] = ref(["http://xxx.pdf"]);<Upload :defaultValue="defaultValue" :size="5" :params="{ fileType: 'xxxxxx' }" :before-change="useUploadImageBeforeChange" />

5. 效果展示

(1)上传
在这里插入图片描述
(2)预览、删除
在这里插入图片描述


总结

接下来会继续分享ant-design常用组件二次封装使用,请持续关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/1472762.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

谷歌地图Google JS API 实现

demo实现 实现源码&#x1f447; // 谷歌地图Google JS API 实现 <template><div class"myMap"><gmp-map :center"center" zoom"15" map-id"ab6b6643adfa1a70"><gmp-advanced-markerv-for"(res, index) in…

python如何不保留小数

1、int() 向下取整&#xff08;内置函数&#xff09; n 3.75 print(int(n)) >>> 3 n 3.25 print(int(n)) >>> 3 2、round() 四舍五入&#xff08;内置函数&#xff09; n 3.75 print(round(n)) >>> 4 n 3.25 print(round(n)) >>> 3 …

Java+前后端分离架构+ MySQL8.0.36产科信息管理系统 产科电子病历系统源码

Java前后端分离架构 MySQL8.0.36产科信息管理系统 产科电子病历系统源码 产科信息管理系统—住院管理 数字化产科住院管理是现代医院管理中的重要组成部分&#xff0c;它利用数字化技术优化住院流程&#xff0c;提升医疗服务质量和效率。以下是对数字化产科住院管理的详细阐述…

NSAT-8000电源模块测试系统提供台式机电源自动化测试方案

在数字化时代&#xff0c;台式机电源的重要性愈发凸显&#xff0c;它不仅是计算机硬件系统的能量心脏&#xff0c;更是保障整个电子生态系统稳定运行的基础。随着人工智能、大数据等技术的飞速发展&#xff0c;计算机系统对电源的性能要求也在不断提高。因此&#xff0c;研究台…

【Linux进程】进程优先级 Linux 2.6内核进程的调度

前言 进程是资源分配的基本单位, 在OS中存在这很多的进程, 那么就必然存在着资源竞争的问题, 操作系统是如何进行资源分配的? 对于多个进程同时运行, 操作系统又是如何调度达到并发呢? 本文将以Linux kernel 2.6为例 , 向大家介绍进程在操作系统中 (OS) 的调度原理; 1. 进程优…

为什么写Python脚本时要加上if __name__ == ‘__main__‘?

目录 一、__name__ 的秘密 二、if __name__ __main__: 的作用 三、代码示例与案例分析 示例一&#xff1a;简单的数学工具模块 示例二&#xff1a;命令行工具 四、实际应用场景 五、进阶应用 1. 插件开发 2. 动态加载模块 3. 交互式与脚本模式切换 六、结论 在Pyth…

阿里云RDS云数据库库表恢复操作

最近数据库中数据被人误删了,记录一下恢复操作方便以后发生时进行恢复. 1.打开控制台&#xff0c;进入云数据库实例. 2.进入实例后 &#xff0c;点击右侧的备份恢复&#xff0c;然后看一下备份时间点&#xff0c;中间这边都是阿里云自动备份的备份集&#xff0c;基本都是7天一备…

优优嗨聚集团:揭秘!轻松化解个人债务危机的实用宝典

在快节奏的现代社会中&#xff0c;个人债务问题日益凸显&#xff0c;成为许多人不得不面对的棘手难题。面对堆积如山的账单和不断增长的利息&#xff0c;我们该如何应对&#xff0c;才能走出债务泥潭&#xff0c;重获财务自由呢&#xff1f;本文将为您揭秘处理个人债务的实用宝…

敏捷实践:需求,做还是不做?哪些先做?做优先级排序时用得最多的3个模型(附实操说明)

在当今快节奏的数字化时代&#xff0c; 敏捷开发已成为众多企业和团队提升竞争力的关键策略。 而在敏捷开发过程中&#xff0c; 优先级排序的重要性不言而喻&#xff0c; 它直接影响着项目的进度、资源分配以及最终的成果。 01 优先级排序听起来是一个很简单的工作&#…

广东这家非标自动化公司居然2台工作站20个设计同时用?

在当今快速发展的制造业中&#xff0c;非标自动化公司凭借其独特的定制化服务&#xff0c;正在逐步改变着传统的生产方式。在日益复杂和高度专业化的非标自动化设计领域&#xff0c;图形工作站的重要性不言而喻。设计师们需要强大的计算能力和高效的运行环境来支持他们的创意工…

开发者评测|操作系统智能助手OS Copilot

操作系统智能助手OS Copilot 文章目录 操作系统智能助手OS CopilotOS Copilot 是什么优势功能 操作步骤创建实验重置密码创建Access Key配置安全组安装 os-copilot环境变量配置功能评测命令行模式多轮交互模式 OS Copilot 产品体验评测反馈OS Copilot 产品功能评测反馈 参考文档…

IDEA导入依赖+Maven配置

Maven安装及配置 安装 安装链接&#xff1a;https://archive.apache.org/dist/maven/maven-3/3.6.3/binaries/ 注&#xff1a;建议不要直接安装最新版本&#xff0c;选用常用、稳定的版本安装即可&#xff0c;比如&#xff1a;3.6.3 配置 1> 配置bash_profile文件 终端输…

VUE3使用antd引入百度地图 实现位置查询,获取地址经纬度

实现效果: 1.index.html 中先引入下 <script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=自己申请的key"></script> 申请密钥key地址:登录百度账号 注册登录后创建应用,根据自己需求选择 2.新建bmp.js文件…

Wormhole Filters: Caching Your Hash on Persistent Memory——泛读笔记

EuroSys 2024 Paper 论文阅读笔记整理 问题 近似成员关系查询&#xff08;AMQ&#xff09;数据结构可以高效地近似确定元素是否在集合中&#xff0c;例如Bloom滤波器[10]、cuckoo滤波器[23]、quotient滤波器[8]及其变体。但AMQ数据结构的内存消耗随着数据规模的增长而快速增长…

模板初阶和string容器

目录 1.模板 函数模板 函数模板的调用规则&#xff1a; 类模板 容器与迭代器 string的简单介绍 iterator&#xff08;迭代器&#xff09; begin()与end() rbegin&#xff08;&#xff09;和rend&#xff08;&#xff09; Capacity&#xff08;容量&#xff09; shrink…

跨境人最怕的封店要怎么规避?

跨境人最怕的是什么&#xff1f;——封店 造成封店的原因很多&#xff0c;IP关联、无版权售卖、虚假发货等等&#xff0c;其中IP关联这个问题导致店铺被封在跨境商家中简直是屡见不鲜 IP关联&#xff0c;是指被海外平台检测到多家店铺开设在同一个站点上的情况。我们知道有些…

微服务框架Kratos学习笔记

环境配置 export GOPROXYhttps://goproxy.cn export GO111MODULEon go get -u github.com/go-kratos/kratos/tool/kratoskratos 工具安装完成 使用kratos命令创建新项目 kratos new kratos-demo看到这个提示&#xff0c;项目创建完成 go mod tidy 拉取项目依赖 生成所有pro…

卫星轨道平面简单认识

目录 一、轨道平面 1.1 轨道根数 1.2 应用考虑 二、分类 2.1 根据运行高度 2.2 根据运行轨迹偏心率 2.3 根据倾角大小 三、卫星星座中的轨道平面 四、设计轨道平面的考虑因素 一、轨道平面 1.1 轨道根数 轨道平面是定义卫星或其他天体绕行另一天体运动的平面。这个平…

python输出个人自我介绍

需求 使用input()函数从键盘输入姓名、年龄&#xff0c;座右铭&#xff0c;并使用print()函数输出到控制台 nameinput(请输入您的姓名&#xff1a;) ageinput(请输入您的年龄&#xff1a;) mottoinput(请输入您的座右铭&#xff1a;) print(------------自我介绍------------…

WAIC上官宣!大模型语料提取工具MinerU正式发布,开源免费“敲”好用

7月4日&#xff0c;2024 WAIC科学前沿全体会议在上海世博中心红厅隆重举行。上海人工智能实验室与商汤科技联合香港中文大学和复旦大学正式发布新一代大语言模型书⽣浦语2.5&#xff08;InternLM2.5&#xff09;&#xff0c;同时全链条工具体系迎来重磅升级&#xff0c;对于大模…