​这篇将介绍如何写一个简单的基于Vue+Element的文件上传控件。

控件将具有

1. 上传队列的列表,显示文件名称,大小等信息,可以显示上传进度实时刷新

2. 取消上传

使用Element的uploader控件,上传文件的行为和样式不用自己全部实现,使代码简化。且有足够的扩展性,文件传输请求的代码可以基于axios完全自己重写。我们只用关心核心代码。

搭建项目框架

首先建立一个空白的项目,引入Element控件库,具体的操作和使用Element控件库请看官方文档:

组件 | Element

后端项目框架的搭建,请阅读:

编写文件上传代码

编写文件上传的帮助类,新建ajaxRequire.ts并键入以下内容:

import axios, { CancelTokenSource } from 'axios'
//发送网络请求
export const request = async (url: string, methods, data: any, onProgress?: (e)=>void, cancelToken?: CancelTokenSource) => {
let token = null
let timeout = 3000;
if (cancelToken) {
token = cancelToken.token
timeout = 0;
}
const service = axios.create()
const re = await service.request({
headers: {'Content-Type': 'multipart/form-data'},
url: url,
method: methods,
data: data,
cancelToken: token,
timeout: timeout,
onUploadProgress: function (progressEvent) { //原生获取上传进度的事件
if (progressEvent.lengthComputable) {
if (onProgress) {
onProgress(progressEvent);
}
}
},
})
return re as any;
} ///获得取消令牌
export const getCancelToken = () => {
const source = axios.CancelToken.source();
return source;
}

onUploadProgress回调函数将在数据传输进度变化的时候触发,携带progressEvent 原生获取上传进度事件参数,progressEvent.lengthComputable用于判断是否可以进行进度计算

axios.CancelToken.source()可以获得一个源,这个源包含一个唯一Id用于标识哪个请求,和一个cancel函数用于取消请求

编写控件

在App.vue中添加核心的控件 <el-upload>

接着添加属性,注意我们将用自己的方法upload替换el-upload中的上传操作,因此设置action="/",

:http-request="upload",如下:

<el-upload
ref="upload"
:limit="10"
multiple
action="/"
:http-request="upload">
</el-upload>

在script中添加上传Dto:一些业务相关的数据在这里定义 比如ownerUserId, fileContainerName等,这些数据可以通过表单与文件数据一并上传

export class CreateFileDto {
id: string;
fileContainerName: string; //文件夹名称
parentId: string; //文件的父Id
ownerUserId: number; //文件的归属用户Id
fileName: string;
mimeType: string;
fileType: number; //文件类型 0:文件夹,1:普通文件
file: any; //文件数据
}

method中添加一些帮助类函数:

methods: {
successMessage(value = "执行成功") {
this.$notify({
title: "成功",
message: value,
type: "success",
});
}, errorMessage(value = "执行错误") {
this.$notify.error({
title: "错误",
message: value,
});
}, FriendlyFileSize(bytes) {
bytes = parseFloat(bytes);
if (bytes === 0) return "0B";
let k = 1024,
sizes = ["B", "KB", "MB", "GB", "TB"],
i = Math.floor(Math.log(bytes) / Math.log(k));
return (bytes / Math.pow(k, i)).toPrecision(3) + sizes[i];
},
}

编写提交前置函数,这里将做验证和生成cancelToken:

beforeUpload(file) {
var token = getCancelToken();
file.cancelToken = token;
let isLt2M = true;
if (this.fileSizeLimit < 0) {
return true;
}
isLt2M = file.size / 1024 / 1024 < this.fileSizeLimit;
if (!isLt2M) {
this.loading = false;
this.errorMessage(`"上传文件大小不能超过 ${this.fileSizeLimit}}MB!"`);
}
return isLt2M;
}

编写upload函数,用于组装请求数据并交给 ajaxRequire 执行上传任务

  async upload(option) {
this.loaded = true;
var model = new CreateFileDto();
var file = option.file;
model.fileName = file.name;
model.fileType = 2;
model.mimeType = file.type;
model.ownerUserId = 1;
model.fileContainerName = "Container1";
model.file = file;
var fd = new FormData(); Enumerable.from(model).forEach((c) => {
fd.append(c.key, c.value);
}); var token = file.cancelToken;
await request(
this.uploadUrl,
"post",
fd,
(e) => {
if (e.total > 0) {
e.percent = (e.loaded / e.total) * 100;
}
option.onProgress(e);
},
token
);
},

将token将作为取消传输的入口交给ajaxRequire ,自己也保留这个对象用于发送取消命令,相当于“一式两份”。

添加el-upload各阶段函数的订阅

:before-upload="beforeUpload"

:on-success="handleSuccess"

:on-remove="handleRemove"

:on-error="handleError"

    handleSuccess(response, file, fileList) {
this.successMessage("上传成功");
this.loading = false;
}, handleError(e, file, fileList) {
this.errorMessage(e);
this.loading = false;
}, handleRemove(file, fileList) {
if (file.raw.cancelToken) {
file.raw.cancelToken.cancel();
}
},

编写上传队列的Html代码:

      <el-button ref="uploadButton">上传</el-button>
<span slot="file" slot-scope="{ file }">
<div class="filelist-item">
<el-row>
<el-col :span="6" class="file-icon-frame">
<i class="el-icon-document file-icon"></i>
</el-col>
<el-col :span="18">
<el-row>
<el-col :span="20">
<label class="file-title">
{{ file.name }}
</label>
</el-col>
<el-col :span="4" style="text-align: right">
<el-button
type="danger"
icon="el-icon-minus"
size="mini"
circle
@click="handleRemove(file)"
></el-button>
</el-col>
<el-col :span="24">
<label class="file-size">
{{ FriendlyFileSize(file.size) }}
</label>
</el-col>
<el-col :span="24">
<el-progress
:text-inside="true"
:stroke-width="26"
:percentage="parseInt(file.percentage, 10)"
:status="
parseInt(file.percentage, 10) == 100 ? 'success' : ''
"
>
</el-progress
></el-col>
</el-row>
</el-col>
</el-row>
</div>
</span>

运行

进入后端项目的目录(api),运行:

dotnet run

前端项目目录(web),运行

yarn serve

运行效果:

完整代码:

file-uploader-sample/web at master · jevonsflash/file-uploader-sample (github.com)

项目地址:

jevonsflash/file-uploader-sample (github.com)

最新文章

  1. nuget packages batch install
  2. Quartz.NET开源作业调度框架系列(五):AdoJobStore保存job到数据库
  3. 药企信息sop
  4. LESS介绍及其与Sass的差异
  5. WGZX:javaScript 学习心得--1
  6. spring3-hibernate3整合
  7. ACM-进阶之路
  8. BZOJ 2301 Problem B(莫比乌斯反演)
  9. HttpHelps类,用来实现Http访问,Post或者Get方式的,直接访问,带Cookie的,带证书的等方式,可以设置代理
  10. jqmobile
  11. ArcEngine 图层无闪烁刷新
  12. J Dp
  13. 从零开始学 Web 之 CSS(三)链接伪类、背景、行高、盒子模型、浮动
  14. WebForm多页面传值跳转
  15. 搞死人的contextRoot;weblogic9.2
  16. mvc5.0-路由
  17. Spark Shuffle原理解析
  18. 移动端 图片切换 轮播(banner)
  19. random随机数应用
  20. 搭建Nexus本地仓库

热门文章

  1. 07模块化设计之top_down
  2. 使用VS Code编译Marlin固件
  3. 12.9 Override
  4. 手把手带你使用EFR32 -- 土壤湿度传感器变身第二形态,以 ZigBee 形态出击
  5. dp:找零问题
  6. 序列化和反序列化&amp;持久化
  7. 去掉一个Vector集合中重复的元素?
  8. 阐述final、finally、finalize的区别?
  9. 可以直接调用 Thread 类的 run ()方法么?
  10. java的泛型hei