[Vue] 写一个简单的文件上传控件

简介: [Vue] 写一个简单的文件上传控件

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

先看效果

控件将具有

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

2. 取消上传

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

先分享一款实用前端面试题库小程序  手机刷题收藏以后用的上     微信搜索     MST题宝库

 

搭建项目框架

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

组件 | Element

后端项目框架的搭建,请阅读:[.Net 6]写一个简单的文件上传控件后端 - 林晓lx - 博客园 (cnblogs.com)

编写文件上传代码

编写文件上传的帮助类,新建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)

标签: Vue, ElementUI

先分享一款实用前端面试题库小程序  手机刷题收藏以后用的上     微信搜索     MST题宝库

相关文章
|
25天前
|
JavaScript API 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
26天前
|
JavaScript 前端开发 开发者
vue 数据驱动视图
总之,Vue 数据驱动视图是一种先进的理念和技术,它为前端开发带来了巨大的便利和优势。通过理解和应用这一特性,开发者能够构建出更加动态、高效、用户体验良好的前端应用。在不断发展的前端领域中,数据驱动视图将继续发挥重要作用,推动着应用界面的不断创新和进化。
|
28天前
|
JavaScript 前端开发 开发者
vue学习第一章
欢迎来到我的博客!我是瑞雨溪,一名热爱前端的大一学生,专注于JavaScript与Vue,正向全栈进发。博客分享Vue学习心得、命令式与声明式编程对比、列表展示及计数器案例等。关注我,持续更新中!🎉🎉🎉
32 1
vue学习第一章
|
28天前
|
JavaScript 前端开发 索引
vue学习第三章
欢迎来到瑞雨溪的博客,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中的v-bind指令,包括基本使用、动态绑定class及style等,希望能为你的前端学习之路提供帮助。持续关注,更多精彩内容即将呈现!🎉🎉🎉
26 1
vue学习第三章
|
28天前
|
缓存 JavaScript 前端开发
vue学习第四章
欢迎来到我的博客!我是瑞雨溪,一名热爱JavaScript与Vue的大一学生。本文介绍了Vue中计算属性的基本与复杂使用、setter/getter、与methods的对比及与侦听器的总结。如果你觉得有用,请关注我,将持续更新更多优质内容!🎉🎉🎉
35 1
vue学习第四章
|
25天前
|
JavaScript 前端开发 开发者
Vue是如何劫持响应式对象的
Vue是如何劫持响应式对象的
22 1
|
25天前
|
JavaScript 前端开发 API
介绍一下Vue中的响应式原理
介绍一下Vue中的响应式原理
27 1
|
28天前
|
JavaScript 前端开发
vue学习第五章
欢迎来到我的博客,我是瑞雨溪,一名热爱JavaScript和Vue的大一学生。自学前端2年半,正向全栈进发。如果你从我的文章中受益,欢迎关注,我将持续分享更多优质内容。你的支持是我最大的动力!🎉🎉🎉
26 1
|
25天前
|
JavaScript 前端开发 开发者
Vue是如何进行组件化的
Vue是如何进行组件化的
|
25天前
|
存储 JavaScript 前端开发
介绍一下Vue的核心功能
介绍一下Vue的核心功能