Vue开发之封装上传文件组件与用法示例

yizhihongxing

Vue开发之封装上传文件组件与用法示例

一、概述

在Vue项目中,我们经常需要使用到上传文件的功能,为了提高代码的可复用性并减少冗余代码,我们可以封装一个通用的上传文件组件。本篇攻略将介绍如何封装上传文件组件以及如何在Vue项目中使用该组件。

二、上传文件组件的封装

  1. 创建 UploadFile.vue 组件文件,并添加如下代码:
<template>
  <div>
    <input type="file" :multiple="multiple" @change="upload">
  </div>
</template>

<script>
export default {
  name: "UploadFile",
  props: {
    multiple: Boolean, // 是否可多选,默认为false
    uploadUrl: String //文件上传接口地址
  },
  methods: {
    upload(e) {
      const formData = new FormData();
      const files = Array.from(e.target.files);
      for (let i = 0; i < files.length; i++) {
        formData.append("files", files[i]);
      }
      // 文件上传接口
      fetch(this.uploadUrl, {
        method: "POST",
        body: formData,
      })
        .then(function (response) {
          return response.json();
        })
        .then(function (data) {
          console.log("文件上传成功");
        })
        .catch(function (error) {
          console.log(error);
        });
    },
  },
};
</script>
  1. 编写更加灵活的 UploadFile.vue 组件,代码如下:
<template>
  <div>
    <input type="file" :multiple="multiple" @change="upload">
    <slot></slot>
  </div>
</template>

<script>
export default {
  name: "UploadFile",
  props: {
    multiple: Boolean,
    uploadUrl: String,
    fileTypes: {
      type: Array,
      default: function () {
        return [".jpg", ".png", ".gif", ".jpeg", ".bmp"]; //文件类型限制,默认是图片类型
      },
    },
    maxCount: {
      type: Number,
      default: 1, //默认为最多上传1个文件
    },
  },
  methods: {
    beforeUpload: function (file) {
      const fileType = file.name.slice(file.name.lastIndexOf("."));
      const isFileTypeAllowed = this.fileTypes.includes(fileType);
      if (!isFileTypeAllowed) {
        alert("文件类型不支持");
        return false;
      }
      if (this.maxCount === 1) {
        return true;
      }
      if (this.maxCount && this.maxCount > this.uploadedFiles.length) {
        return true;
      } else {
        alert(`最多只能上传${this.maxCount}个文件`);
        return false;
      }
    },
    upload(e) {
      const formData = new FormData();
      const files = Array.from(e.target.files);
      if (!files.length) return;
      for (let i = 0; i < files.length; i++) {
        if (this.beforeUpload(files[i])) {
          formData.append("files", files[i]);
        }
      }
      // 文件上传接口
      fetch(this.uploadUrl, {
        method: "POST",
        body: formData,
      })
        .then(function (response) {
          return response.json();
        })
        .then((data) => {
          if (data.success) {
            this.$emit("success", data);
          } else {
            this.$emit("fail", data);
          }
          this.$refs.fileInput.value = ""; //清空input的value值,避免上传同一个文件的时候无法触发change事件
        })
        .catch(function (error) {
          console.log(error);
        });
    },
    getUploadedFiles: function () {
      const files = Array.from(this.$refs.fileInput.files);
      const uploadedFiles = [];
      for (let i = 0; i < files.length; i++) {
        uploadedFiles.push({
          name: files[i].name,
          url: URL.createObjectURL(files[i]),
        });
      }
      this.uploadedFiles = uploadedFiles;
    },
    handleRemove(file) {
      this.uploadedFiles.splice(this.uploadedFiles.indexOf(file), 1);
    },
  },
  data() {
    return {
      uploadedFiles: [], //已上传的文件
    };
  },
  mounted() {
    if (this.$slots.default) {
      this.$slots.default.forEach((vnode) => {
        if (vnode.tag) {
          vnode.elm.addEventListener("click", () => {
            this.$refs.fileInput.click();
          });
        }
      });
    }
  },
};
</script>

<style>
.hide-input-file {
  position: absolute;
  visibility: hidden;
  width: 0;
  height: 0;
}
.uploaded-file {
  margin-right: 10px;
  display: inline-block;
  vertical-align: middle;
  position: relative;
  cursor: pointer;
}
.uploaded-file .file-name {
  font-size: 14px;
  max-width: 200px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  display: inline-block;
  vertical-align: middle;
  margin-left: 5px;
  cursor: pointer;
  -webkit-touch-callout: none; /* iOS Safari禁止长按链接与图片弹出上下文菜单 */
}
.uploaded-file .close-icon {
  display: inline-block;
  vertical-align: middle;
  position: absolute;
  top: 0;
  right: -10px;
  width: 20px;
  height: 20px;
  text-align: center;
  line-height: 20px;
  background-color: rgba(0, 0, 0, 0.4);
  border-radius: 50%;
  color: #fff;
  cursor: pointer;
  transition: all 0.3s;
  user-select: none;
  -webkit-touch-callout: none;
}
.uploaded-file .close-icon:hover {
  background-color: rgba(0, 0, 0, 0.6);
  transform: scale(1.2);
}
</style>

三、使用示例

  1. 在Vue项目中引入UploadFile.vue 组件
<template>
  <div>
    <upload-file
      :multiple="true"
      :uploadUrl="'/file/upload' + '?access_token=' + accessToken"
      @success="handleUploadSuccess"
      @fail="handleUploadFail"
    >
      <div class="upload-file-btn">上传文件</div>
    </upload-file>
  </div>
</template>

<script>
import UploadFile from "@/components/UploadFile.vue";
export default {
  name: "FileUploadPage",
  components: { UploadFile },
  data() {
    return {
      accessToken: "",
    };
  },
  methods: {
    handleUploadSuccess(data) {
      console.log("上传成功", data);
    },
    handleUploadFail(data) {
      console.log("上传失败", data);
    },
  },
  mounted() {
    this.accessToken = localStorage.getItem("access_token");
  },
};
</script>

在以上示例中,我们引入了 UploadFile 组件,并给组件传递多个 props 值,它们分别是:multiple(是否可多选,默认为 false)、uploadUrl(文件上传接口地址)。我们通过添加额外的 slot 到组件中,来定制自己的上传按钮。

  1. 使用 UploadFile.vue 组件上传文件限制类型和数量
<template>
  <div>
    <upload-file
      :multiple="true"
      :uploadUrl="'/file/upload' + '?access_token=' + accessToken"
      :max-count="3"
      :file-types="['.jpg', '.png']"
      @success="handleUploadSuccess"
      @fail="handleUploadFail"
    >
      <div class="upload-file-btn">上传图片(最多三张)</div>
    </upload-file>
    <div>
      <div class="uploaded-file" v-for="file in uploadedFiles" :key="file.name">
        <img :src="file.url" alt="上传的图片" width="100" height="100" />
        <div class="file-name">{{ file.name }}</div>
        <div class="close-icon" @click="handleRemove(file)">X</div>
      </div>
    </div>
  </div>
</template>

<script>
import UploadFile from "@/components/UploadFile.vue";
export default {
  name: "FileUploadPage",
  components: { UploadFile },
  data() {
    return {
      uploadedFiles: [],
      accessToken: "",
    };
  },
  methods: {
    handleUploadSuccess(data) {
      console.log("上传成功", data);
      this.getUploadedFiles();
    },
    handleUploadFail(data) {
      console.log("上传失败", data);
    },
    getUploadedFiles() {
      this.$refs.uploadedFiles = this.$refs.uploadFile.uploadedFiles;
      this.uploadedFiles = this.$refs.uploadFile.uploadedFiles;
    },
    handleRemove(file) {
      this.$refs.uploadFile.handleRemove(file);
      this.uploadedFiles = this.$refs.uploadFile.uploadedFiles;
    },
  },
  mounted() {
    this.accessToken = localStorage.getItem("access_token");
  },
};
</script>

在以上示例中,我们除了给 UploadFile 组件传送常规的属性外,额外传递了两个属性:file-types和max-count,它们表示的是文件上传时允许的文件类型和文件数量。在页面中,我们绑定了success和fail事件,可以根据上传结果做出相应的处理。在上传完成之后,我们还会根据上传成功的数据,动态展示出已经上传的文件。

至此,我们就完成了一个通用的上传文件组件,并实现了在Vue项目中使用该组件的示例。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Vue开发之封装上传文件组件与用法示例 - Python技术站

(0)
上一篇 2023年5月28日
下一篇 2023年5月28日

相关文章

  • Vue获取表单数据的方法

    当使用Vue开发Web应用时,我们经常需要从表单中获取用户输入的数据。下面是几种Vue获取表单数据的方法的完整攻略: 1.使用v-model指令获取表单数据 我们可以在表单元素上使用v-model指令,Vue会自动为我们管理和更新表单元素的值。要使用v-model指令获取表单值,我们需要为表单元素绑定v-model指令,将其值绑定到Vue组件实例中的一个属性…

    Vue 2023年5月27日
    00
  • vuex存储数据的几种方法实例详解

    我为您详细讲解“Vuex存储数据的几种方法实例详解”的攻略。 什么是Vuex Vuex是Vue.js应用程序中的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。 组件中存储数据的问题 在Vue.js应用程序中,对于一个组件来说,如果它的状态发生变化,这个变化对于其他组件是不可见的;如果多个组件共享同一…

    Vue 2023年5月28日
    00
  • 创建和运行Vue.js项目方法demo

    让我们来讲解如何创建和运行Vue.js项目。下面是完整攻略: 1. 安装 Node.js 安装Vue.js需要先安装Node.js。Node.js可以在Node.js官网上进行下载安装。选择相应平台的安装包进行下载,并按照提示进行安装。 安装完成后,可以在命令行中输入node -v和npm -v查看Node.js和npm的版本号,确认安装成功。 2. 创建V…

    Vue 2023年5月27日
    00
  • 简单谈谈Vue中的diff算法

    简单谈谈Vue中的diff算法 什么是Vue中的diff算法 在Vue.js中,使用虚拟DOM(Virtual DOM)来优化DOM操作的效率。然而,每当Vue组件内部数据发生变化时,都需要比较新旧两个虚拟DOM树来找出变化的部分并最终更新到DOM上。这个过程就是Vue中的diff算法。 Vue中的diff算法原理 Vue中的diff算法通过递归地比较新虚拟…

    Vue 2023年5月28日
    00
  • Springboot vue导出功能实现代码

    那我为您详细讲解一下“Springboot vue导出功能实现代码”的完整攻略。 1. 环境准备 首先需要准备好以下环境: JDK 8+ Maven 3+ Vue.js 2+ Element-UI 2+ axios 0.19+ 2. 前端实现 在前端页面中,我们需要添加一个导出按钮,当用户点击该按钮时,触发导出操作。 <el-button type=&…

    Vue 2023年5月27日
    00
  • Vue 使用formData方式向后台发送数据的实现

    下面是关于“Vue 使用formData方式向后台发送数据的实现”的详细攻略说明。 一、什么是FormData? FormData 是在使用 AJAX 时发送表单数据的技术。它是一种用于传输表单文件和表单数据的对象。 二、Vue上使用FormData方式向后台发送数据的实现 1. 在Vue中使用axios 在 Vue 中发送 AJAX 请求通常使用 axio…

    Vue 2023年5月28日
    00
  • vue3中的伸缩菜单组件

    下面我将详细讲解“Vue3中的伸缩菜单组件”的完整攻略。 一、概述 伸缩菜单组件是一个常用的组件,它可以让用户在界面上添加一些操作面板,具体实现方式就是点击按钮后,菜单面板会出现或者隐藏。在Vue3中,我们可以使用自定义指令实现这种效果。 二、实现步骤 以下是实现伸缩菜单的具体步骤: 1. 创建Vue3应用 我们需要先创建一个Vue3应用,方法如下: vue…

    Vue 2023年5月28日
    00
  • 浅谈webpack性能榨汁机(打包速度优化)

    我来详细讲解一下“浅谈webpack性能榨汁机(打包速度优化)”的完整攻略。 一、前言 在现在的前端开发中,使用Webpack打包已成为主流,但是Webpack打包速度的问题一直都是众多开发者关注的重点。本文将从Webpack的优化策略和实战两个方面来为大家讲解如何优化Webpack的打包速度。 二、Webpack的优化策略 尽可能少地使用loader 在W…

    Vue 2023年5月28日
    00
合作推广
合作推广
分享本页
返回顶部