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

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 实现自定义公共组件及提取公共的方法”的完整攻略。 1. 自定义公共组件 1.1 创建与引入组件 Vue 框架提供了组件化的机制,用户可以通过自定义组件的方式进行开发。下面是一个简单的自定义组件的例子,我们可以创建一个 HelloWorld 组件: <template> <div> <h1>{{ …

    Vue 2023年5月28日
    00
  • vue如何动态实时的显示时间浅析

    那我来分享一下Vue.js实时显示时间的攻略。 1. 使用Vue.js的生命周期函数 Vue.js生命周期函数是指Vue实例在不同阶段会自动执行的一系列函数。我们可以通过生命周期函数来实现实时显示时间的功能。 具体步骤如下: 1.1 创建一个Vue实例 使用Vue.js创建一个Vue实例,在data属性中新增一个变量time,用于存储当前时间,代码如下: v…

    Vue 2023年5月28日
    00
  • 在Vue当中同时配置多个路由文件的方法案例代码

    Vue Router是Vue.js官方提供的路由管理器。在项目的开发过程中,我们可能会有多个路由文件,如何同时配置多个路由文件呢?本文将详细介绍在Vue中同时配置多个路由文件的方法案例代码。 1. 创建路由实例 在Vue中,我们可以通过new VueRouter({})来创建路由实例。如果需要同时使用多个路由文件,我们可以将每个路由文件的配置对象都单独定义成…

    Vue 2023年5月28日
    00
  • vue 文件目录结构详解

    下面我为您详细讲解一下Vue文件目录结构的完整攻略。 目录结构说明 在Vue项目创建完成后,我们会看到类似于下面的目录结构: ├── node_modules // 存放整个项目的依赖库 ├── public // 静态资源文件夹,存放系统所需的静态资源。例如图像文件等 │ ├── index.html // 入口页面 ├── src // 真正的代码仓库,…

    Vue 2023年5月28日
    00
  • 浅谈Vue的加载顺序探讨

    浅谈Vue的加载顺序探讨 在使用Vue时,了解其加载顺序是非常重要的。本文将从Vue实例的创建与挂载、组件的异步与同步加载以及动态组件等角度探讨Vue的加载顺序。 Vue实例的创建与挂载 当我们创建并挂载一个Vue实例时,Vue的加载顺序如下: 首先Vue会调用Vue._init()方法进行实例的初始化,此时尚未渲染DOM。 紧接着Vue会调用$mount(…

    Vue 2023年5月29日
    00
  • vue-cli+webpack项目打包到服务器后,ttf字体找不到的解决操作

    这是一个常见的问题,通常是因为打包后的字体路径不正确导致的。以下是解决这个问题的完整攻略: 问题分析 首先,我们需要分析问题的原因。这个问题通常是由于字体文件路径不正确导致的。在开发环境下,字体文件会被正确加载,但是在打包后部署到服务器上时,字体文件的路径可能会错误地指向本地资源而无法加载。因此,我们需要确保字体文件在打包后可以正确被访问到。 解决方法 下面…

    Vue 2023年5月28日
    00
  • 对Vue3中reactive的深入理解

    当我们在Vue3中使用reactive函数时,需要了解以下几个概念: reactive函数用于将数据转换为响应式数据对象,返回一个Proxy代理对象,该对象会拦截对其属性的所有读取和修改操作,从而实现响应式更新 ref函数用于将基础类型数据转换为响应式数据对象,返回一个Ref对象。Ref对象和Proxy对象一样也可以在模板或者JS代码中使用,并且也会自动追踪…

    Vue 2023年5月28日
    00
  • Vue 内置指令梳理总结

    “Vue 内置指令梳理总结”是一篇介绍 Vue 框架内置指令的文章。在这篇文章中,我将会讲解 Vue 框架内置指令包括 v-model、v-show、v-if、v-for 等等的用法,以及每个指令的使用场景、注意事项等等。下面是本篇文章的详细攻略。 1. 指令的基本概念 指令是指 Vue 框架提供的一种特殊的 HTML 属性,通过以 v- 开头的命名来表示。…

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