在我们实际项目开发过程中,往往需要根据实际情况,对组件进行封装,以更简便的在界面代码中使用,在实际的前端应用中,适当的组件封装,可以减少很多重复的界面代码,并且能够非常简便的使用,本篇随笔介绍基于ElementPlus的上传组件进行封装。

1、El-Upload上传组件的使用场景及数据库设计

在官网地址https://element-plus.org/zh-CN/component/upload.html上有关于该组件的详细使用代码案例。

大概有个场景我需要根据需要展示文件的,一个是文件展示方式(非图片格式)。

一种是肖像方式处理。

一种方式是图片缩略图列表方式。

还有就是支持拖动方式上传。

我目前大概就是想到应用这几种方式,细节的地方可以根据需要进行微调即可。

一般来说,我们附件信息是单独存储在一个表里面的,附件则是存储在相应的文件系统或者FTP目录中。如果需要了解后端不同方式的文件上传方式,可以了解随笔《基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

而实际我们业务表里面,只需要存在一个字符串字段,它是一串GUID的值,用于引用单个或者多个附件列表的AttahmentGUID值即可。

在前端界面使用的的时候,我则希望自定义的组件使用的时候,尽量简单,因此对于附件上传的URL地址、Upload组件的相关设置,应该屏蔽在自定义组件即可,组件只需要提供一个v-model的绑定值和一些需要的属性即可。

2、文件上传后端处理

在介绍前端上传组件自定义前,我们需要提供一个上传文件的URL地址给前端,接收前端的文件流,以及相关FormData里面的参数值。

后端上传处理的函数定义如下所示

        /// <summary>
/// 多文件上传处理(自动根据配置文件选择合适的上传方式)
/// </summary>
/// <param name="guid">附件组GUID</param>
/// <param name="folder">指定的上传目录</param>
/// <returns></returns>
[RequestSizeLimit(100000000)] //请求正文最大大小100M
[HttpPost]
[Route("postupload")]
public async Task<List<ResponseFileInfo>> PostUpload()

其中 ResponseFileInfo 是我们定义一个返回给前端使用的对象,记录文件的名称、URL,id信息。

    /// <summary>
/// 上传后文件返回的结果信息
/// </summary>
public class ResponseFileInfo
{
/// <summary>
/// 默认构造函数
/// </summary>
public ResponseFileInfo() { } /// <summary>
/// 参数化构造函数
/// </summary>
/// <param name="id"></param>
/// <param name="name"></param>
/// <param name="url"></param>
public ResponseFileInfo(string id, string name, string url)
{
this.Id = id;
this.Name = name;
this.Url = url;
} /// <summary>
/// 记录ID
/// </summary>
public string Id { get; set; }
/// <summary>
/// 文件名称
/// </summary> public string Name { get; set; } /// <summary>
/// 文件路径
/// </summary>
public string Url { get; set; }
}

在后端上传处理中,我们可以通过HTTP上下文获得传过来的对应参数和文件列表信息,如下代码所示。

        public async Task<List<ResponseFileInfo>> PostUpload()
{
var httpContext = this.HttpContext;
string guid = httpContext.Request.Form["guid"];//input.guid;
string folder = httpContext.Request.Form["folder"];//input.folder;
var files = httpContext.Request.Form.Files;

最后根据文件信息和相关参数,构建附件数据库信息,以及存储文件就可以了,如下代码所示。

3、文件上传组件的前端封装和处理

对于编辑状态下的前端处理,我们只需要绑定v-model的值,以及指定的一些参数就可以了。

如果是禁止上传的详细展示,可以设置disabled属性为true就可以了

<el-form-item label="资料文档">
<my-upload v-model="viewForm.attachGUID" :data="{ guid: viewForm.attachGUID, folder: '用户图片' }" disabled />
</el-form-item>

用户界面展示如下所示。

通过简单的封装,我们就可以在极少代码的基础上定制自己的功能界面了。易于阅读和维护,同时也有助于我们后面通过代码生成工具的方式快速生成相关的代码。

自定义组件,我们根据需要定义一些属性,并对它设置默认值,如下所示代码。

<script setup lang="ts">
import { reactive, ref, onMounted, watch, computed, getCurrentInstance} from "vue"; import { ElMessage, ElMessageBox } from "element-plus";
import type { UploadInstance, UploadProps, UploadUserFile } from "element-plus";
import { Plus, UploadFilled } from "@element-plus/icons-vue";
import { isNullOrUnDef, isEmpty } from "/@/utils/is";
import fileupload from "/@/api/fileupload"; defineOptions({ name: "MyUpload" }); //声明Props的接口类型
interface Props {
modelValue?: string; // 接受外部v-model传入的值,记录的AttachGUID值
data?: Record<string, any>; //上传时附带的额外参数: {a:b}
headers?: Headers | Record<string, any>; //设置上传的请求头部
listType?: "text" | "picture" | "picture-card"; //文件列表的类型 disabled?: boolean; // 是否禁用
multiple?: boolean; // 是否支持多选文件
limit?: number; // 最大允许上传个数
fileSize?: number; // 大小限制(MB)
fileType?: Array<string>; // 文件类型, 例如['png', 'jpg', 'jpeg']
isShowTip?: boolean; // 是否显示提示
showFileList?: boolean; //是否显示文件列表
withCredentials?: boolean; //支持发送 cookie 凭证信息
isAvatarUpload?: boolean; // 是否是头像上传
drag?: boolean; //是否启用拖拽上传
buttonText?: string; //按钮文本
}
//使用默认值定义Props
const props = withDefaults(defineProps<Props>(), {
modelValue: "", //对应自定义组件的v-model的值
data: () => {
return null;
},
headers: () => {
//用于上传文件的身份认证
return { Authorization: "Bearer " + getAccessToken() };
},
listType: "text", //"text" | "picture" | "picture-card" disabled: false,
multiple: false,
// limit: 10,
fileSize: 2, //MB
fileType: () => {
return ["png", "jpg", "jpeg", "gif"];
},
isShowTip: true,
showFileList: true,
withCredentials: true, //支持发送 cookie 凭证信息
isAvatarUpload: false, //头像上传方式
drag: false, //是否启用拖拽上传
buttonText: "单击上传", });
//定义触发事件
const emit = defineEmits(["error", "success", "remove", "change"]);

在我们展示组件的时候,我们根据v-model绑定的modelValue值进行加载附件列表或者图片信息,

//挂载的时候初始化数据
onMounted(async () => {
if (!isEmpty(props.modelValue)) {
// 使用字典类型,从服务器请求数据
await fileupload.GetByAttachGUID(props.modelValue).then(data => {
// console.log(data);
if (data.length > 0) {
var list: Array<UploadUserFile> = [];
data.map(item => {
let url = getUrl(item);
let { id, fileName, fileExtend } = item; // 结构对象属性
list.push({
name: fileName,
url: url,
uid: id
});
}); fileList.value = list;
//如果是头像上传模式,显示最后一个图片
if (props.isAvatarUpload) {
avatarImageUrl.value = list[0]?.url;
}
}
});
}
});

在预览文件的时候,我们判断,如果是图片文件,就打开窗口展示图片,否则就下载附件即可。

//预览文件
const handlePreview: UploadProps["onPreview"] = uploadFile => {
// console.log(uploadFile);
// 当格式为图片就预览图片,否则下载文件
let filename = uploadFile.name;
let fileurl = uploadFile.url;
let fileExtension = ""; // 校检文件类型
var imageTypes = ["png", "jpg", "jpeg", "gif"];
if (filename.lastIndexOf(".") > -1) {
fileExtension = filename.slice(filename.lastIndexOf(".") + 1);
}
const isTypeOk = imageTypes.some(type => {
if (fileExtension && fileExtension.indexOf(type) > -1) return true;
return false;
}); if (isTypeOk) {
//预览图片
dialogImageUrl.value = fileurl;
dialogTitle.value = filename;
dialogVisible.value = true;
} else {
//下载文件
dialogVisible.value = false;
// openWindow(fileurl, { target: "_self" });
window.open(fileurl, "_self");
}
};

移除文件的时候,我们根据文件的id,在数据库后端进行删除附件和附件信息。

//移除文件前操作
const beforeRemove: UploadProps["beforeRemove"] = (uploadFile, uploadFiles) => {
// console.log(uploadFile);
//${uploadFile.name}
return ElMessageBox.confirm(`确认删除该文件吗?`).then(
async () => {
var result = false;
var id = uploadFile.uid;
if (!isEmpty(id)) {
result = await fileupload.Delete(id);
}
return result;
},
() => false
);
};

系列文章:

基于SqlSugar的开发框架的循序渐进介绍(1)--框架基础类的设计和使用

基于SqlSugar的开发框架循序渐进介绍(2)-- 基于中间表的查询处理

基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理

基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口

基于SqlSugar的开发框架循序渐进介绍(7)-- 在文件上传模块中采用选项模式【Options】处理常规上传和FTP文件上传

基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

基于SqlSugar的开发框架循序渐进介绍(9)-- 结合Winform控件实现字段的权限控制

基于SqlSugar的开发框架循序渐进介绍(10)-- 利用axios组件的封装,实现对后端API数据的访问和基类的统一封装处理

基于SqlSugar的开发框架循序渐进介绍(11)-- 使用TypeScript和Vue3的Setup语法糖编写页面和组件的总结

基于SqlSugar的开发框架循序渐进介绍(12)-- 拆分页面模块内容为组件,实现分而治之的处理

基于SqlSugar的开发框架循序渐进介绍(13)-- 基于ElementPlus的上传组件进行封装,便于项目使用的更多相关文章

  1. 基于SqlSugar的开发框架循序渐进介绍(14)-- 基于Vue3+TypeScript的全局对象的注入和使用

    刚完成一些前端项目的开发,腾出精力来总结一些前端开发的技术点,以及继续完善基于SqlSugar的开发框架循序渐进介绍的系列文章,本篇随笔主要介绍一下基于Vue3+TypeScript的全局对象的注入和 ...

  2. 基于SqlSugar的开发框架循序渐进介绍(17)-- 基于CSRedis实现缓存的处理

    在一个应用系统的开发框架中,往往很多地方需要用到缓存的处理,有些地方是为了便于记录用户的数据,有些地方是为了提高系统的响应速度,如有时候我们在发送一个短信验证码的时候,可以在缓存中设置几分钟的过期时间 ...

  3. 基于SqlSugar的开发框架循序渐进介绍(20)-- 在基于UniApp+Vue的移动端实现多条件查询的处理

    在做一些常规应用的时候,我们往往需要确定条件的内容,以便在后台进行区分的进行精确查询,在移动端,由于受限于屏幕界面的情况,一般会对多个指定的条件进行模糊的搜索,而这个搜索的处理,也是和前者强类型的条件 ...

  4. 基于SqlSugar的开发框架循序渐进介绍(21)-- 在工作流列表页面中增加一些转义信息的输出,在后端进行内容转换

    有时候,为了给前端页面输出内容,有时候我们需要准备和数据库不一样的实体信息,因为数据库可能记录的是一些引用的ID或者特殊字符,那么我们为了避免前端单独的进行转义处理,我们可以在后端进行统一的格式化后再 ...

  5. 基于SqlSugar的开发框架循序渐进介绍(3)-- 实现代码生成工具Database2Sharp的整合开发

    我喜欢在一个项目开发模式成熟的时候,使用代码生成工具Database2Sharp来配套相关的代码生成,对于我介绍的基于SqlSugar的开发框架,从整体架构确定下来后,我就着手为它们量身定做相关的代码 ...

  6. 基于SqlSugar的开发框架循序渐进介绍(4)-- 在数据访问基类中对GUID主键进行自动赋值处理

    我们在设计数据库表的时候,往往为了方便,主键ID一般采用字符串类型或者GUID类型,这样对于数据库表记录的迁移非常方便,而且有时候可以在处理关联记录的时候,提前对应的ID值.但有时候进行数据记录插入的 ...

  7. 基于SqlSugar的开发框架循序渐进介绍(5)-- 在服务层使用接口注入方式实现IOC控制反转

    在前面随笔,我们介绍过这个基于SqlSugar的开发框架,我们区分Interface.Modal.Service三个目录来放置不同的内容,其中Modal是SqlSugar的映射实体,Interface ...

  8. 基于SqlSugar的开发框架循序渐进介绍(6)-- 在基类接口中注入用户身份信息接口

    在基于SqlSugar的开发框架中,我们设计了一些系统服务层的基类,在基类中会有很多涉及到相关的数据处理操作的,如果需要跟踪具体是那个用户进行操作的,那么就需要获得当前用户的身份信息,包括在Web A ...

  9. 基于SqlSugar的开发框架循序渐进介绍(8)-- 在基类函数封装实现用户操作日志记录

    在我们对数据进行重要修改调整的时候,往往需要跟踪记录好用户操作日志.一般来说,如对重要表记录的插入.修改.删除都需要记录下来,由于用户操作日志会带来一定的额外消耗,因此我们通过配置的方式来决定记录那些 ...

随机推荐

  1. python 通过线上API查询ip归属地

    API为国外API,频率限制1分钟45个ip 脚本如下 1 #!/usr/bin/env python3 2 #-*-coding:utf-8-*- 3 4 import requests,re,js ...

  2. CSAPP 之 CacheLab 详解

    前言 本篇博客将会介绍 CSAPP 之 CacheLab 的解题过程,分为 Part A 和 Part B 两个部分,其中 Part A 要求使用代码模拟一个高速缓存存储器,Part B 要求优化矩阵 ...

  3. 710. Random Pick with Blacklist - LeetCode

    Question 710. Random Pick with Blacklist Solution 题目大意:给一个N,表示一个范围[0,N),给一个黑名单列表blacklist,其中blacklis ...

  4. 好客租房49-组件的props(特点)

    特点 1可以给组件传递任意类型的数据 2props是只读的对象 只能读取属性的值 无法修改对象 3注意:使用类组件时 如果写了构造函数 应该将props传递给super() 否则 无法在构造函数 中获 ...

  5. MySQL数据库和Oracle数据库的区别

    Mysql数据库 由瑞典 MySQL AB 公司开发,目前属于 Oracle 公司.是一种中小型的关系型数据库. MySQL 数据库体积小.速度快.总体拥有成本低.开放源代码,其有着广泛的应用,一般中 ...

  6. IDEA快捷生成循环♻️

    itar 生成array for代码块 //itar for (int i = 0; i < array.length; i++) { = array[i]; } itco 生成Collecti ...

  7. 【单片机】CH32V103C8T6 ——窗口看门狗

    本章教程通过串口调试助手打印显示程序运行状态,具体现象如下: 若计数器值在上窗口值和下窗口值0X40之间的时候,进行喂狗操作,计数器重新计数,程序正常运行,串口打印显示:The program run ...

  8. 前端向后端传递formData类型的二进制文件

    // 获取到的文件file类型转换为formData类型 let formData = new FormData(); formData.append("file", file文件 ...

  9. Codeforces Round #773 (Div. 2)

    这一场打的非常一般,不过把D想出来了(当然只剩10min没有写出来). A.Hard Way 题意:(很怪的题,我读题读半天)给你一个三角形(端点都在整数点上),问从x轴往上划线(不一定垂直)画不到的 ...

  10. [算法学习] 换根dp

    换根dp 一般来说,我们做题的树都是默认 \(1\) 为根的.但是有些题目需要计算以每个节点为根时的内容. 朴素的暴力:以每个点 \(u\) 作为 \(root\) 暴力dfs下去,复杂度\(O(n^ ...