vue封装组件之上传图片组件

下面我将详细讲解“vue封装组件之上传图片组件”的完整攻略。

1. 简介

上传图片组件是Web开发中常用的组件之一,因此我们也需要封装一个通用的上传图片组件供其他开发者使用。本文将使用Vue.js框架,并结合element-ui组件库,来实现上传图片组件的封装。

2. 基本结构

上传图片组件需要包含以下基本结构:

  1. 文件上传的表单项
  2. 上传进度条
  3. 预览已上传图片
  4. 删除已上传图片按钮
  5. 上传图片按钮

具体结构代码如下:

<template>
  <div>
    <!-- 文件上传表单项 -->
    <el-upload
      class="upload-file"
      :action="uploadUrl"
      :show-file-list="false"
      :data="formData"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      :on-progress="handleProgress"
      ref="upload"
    >
      <!-- 上传图片按钮 -->
      <el-button
        size="medium"
        type="primary"
        :disabled="disabled"
      >
        <slot name="upload-btn">上传图片</slot>
      </el-button>
      <!-- 上传进度条 -->
      <el-progress
        class="upload-progress"
        :percentage="uploadPercentage"
        :stroke-width="2"
        :color="customColor"
        :hide-info="true"
        :show-text="false"
        :status="status"
      ></el-progress>
    </el-upload>
    <!-- 上传成功的图片预览及删除按钮 -->
    <div class="view-file-list" v-if="fileList && fileList.length > 0">
      <el-card
        shadow="hover"
        v-for="(file, index) in fileList"
        :key="index"
        class="view-card"
      >
        <img
          :src="file.url || file.preview"
          class="view-img"
        />
        <el-button
          size="small"
          type="danger"
          class="delete-btn"
          icon="el-icon-delete"
          @click.prevent="handleDelete(index)"
        ></el-button>
      </el-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'UploadImage',
  props: {
    uploadUrl: {
      type: String,
      required: true
    },
    formData: {
      type: Object,
      default: () => ({})
    },
    disabled: {
      type: Boolean,
      default: false
    },
    customColor: {
      type: String,
      default: ''
    },
    fileSizeLimit: {
      type: Number,
      default: 2
    },
    fileTypeLimit: {
      type: Array,
      default: () => ['jpg', 'jpeg', 'png', 'gif']
    }
  },
  data() {
    return {
      fileList: [],
      uploadPercentage: 0,
      status: 'warning'
    }
  },
  methods: {
    beforeUpload(file) {
      const isLtSize = file.size / 1024 / 1024 < this.fileSizeLimit
      const fileTypeArr = file.name.split('.')
      const fileType = fileTypeArr[fileTypeArr.length - 1].toLowerCase()
      const isFileType = this.fileTypeLimit.includes(fileType)
      if (!isLtSize) {
        this.$message.error(`上传图片不能超过 ${this.fileSizeLimit}MB!`)
        return false
      }
      if (!isFileType) {
        this.$message.error('上传图片格式必须是' + this.fileTypeLimit.join('、'))
        return false
      }
      return true
    },
    handleSuccess(response, file, fileList) {
      if (response.code !== '0') {
        this.$message.error('上传失败')
        return
      }
      const { data } = response
      if (data && data.length > 0) {
        this.fileList.push({
          url: data[0].url,
          name: file.name
        })
        this.status = 'success'
      }
    },
    handleProgress(event, file, fileList) {
      this.uploadPercentage = Math.floor(event.percent)
    },
    handleDelete(index) {
      this.fileList.splice(index, 1)
      this.$refs.upload.clearFiles()
      this.uploadPercentage = 0
      this.status = 'warning'
    }
  },
  watch: {
    fileList: {
      handler(val) {
        this.$emit('update:fileList', val)
      },
      deep: true
    }
  }
}
</script>

<style scoped>
.upload-file {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  width: 180px;
  height: 180px;
  margin-bottom: 20px;
  border: 1px dashed #d9d9d9;
  border-radius: 2px;
}
.view-file-list {
  display: flex;
  flex-wrap: wrap;
  margin-top: 10px;
  margin-bottom: 10px;
}
.view-card {
  display: flex;
  justify-content: center;
  align-items: center;
  margin-right: 10px;
  margin-bottom: 10px;
  width: 180px;
  height: 180px;
}
.view-img {
  max-width: 100%;
  max-height: 100%;
  border-radius: 2px;
}
.delete-btn {
  position: absolute;
  top: 5px;
  right: 5px;
}
</style>

3. 基本使用

使用上传图片组件,只需要在Vue实例中引入该组件,并传入必要的参数即可。

<template>
  <div>
    <upload-image
      :upload-url="uploadUrl"
      :form-data="formData"
      :disabled="disabled"
      :file-size-limit="fileSizeLimit"
      :file-type-limit="fileTypeLimit"
      :custom-color="customColor"
      v-model="fileList"
    >
      <template #upload-btn>
        <i class="el-icon-plus"></i>
        上传
      </template>
    </upload-image>
  </div>
</template>

<script>
import UploadImage from '@/components/UploadImage'

export default {
  name: 'Example',
  components: {
    UploadImage
  },
  data() {
    return {
      uploadUrl: '/upload/image',
      formData: {
        userid: '0001'
      },
      disabled: false,
      fileList: [],
      fileSizeLimit: 5,
      fileTypeLimit: ['jpg', 'jpeg', 'png', 'gif'],
      customColor: '#409eff'
    }
  }
}
</script>

该示例演示了上传图片组件的基本使用方法,此时我们便可以在页面上看到一个上传按钮,同时也可以预览已上传的图片。

4. 示例说明

实现多图上传

在上面的组件基础上,我们可以使用el-upload组件的multiple属性,来实现多张图片上传。

<template>
  <div>
    <el-upload
      class="upload-file"
      :action="uploadUrl"
      :show-file-list="false"
      :data="formData"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      :on-progress="handleProgress"
      :multiple="true"
      ref="upload"
    >
      <el-button
        size="medium"
        type="primary"
        :disabled="disabled"
      >
        <slot name="upload-btn">上传图片</slot>
      </el-button>
      <el-progress
        class="upload-progress"
        :percentage="uploadPercentage"
        :stroke-width="2"
        :color="customColor"
        :hide-info="true"
        :show-text="false"
        :status="status"
      ></el-progress>
    </el-upload>
    <div class="view-file-list" v-if="fileList && fileList.length > 0">
      <el-card
        shadow="hover"
        v-for="(file, index) in fileList"
        :key="file.url + index"
        class="view-card"
      >
        <img
          :src="file.url || file.preview"
          class="view-img"
        />
        <el-button
          size="small"
          type="danger"
          class="delete-btn"
          icon="el-icon-delete"
          @click.prevent="handleDelete(index)"
        ></el-button>
      </el-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'UploadImage',
  props: {
    uploadUrl: {
      type: String,
      required: true
    },
    formData: {
      type: Object,
      default: () => ({})
    },
    disabled: {
      type: Boolean,
      default: false
    },
    customColor: {
      type: String,
      default: ''
    },
    fileSizeLimit: {
      type: Number,
      default: 2
    },
    fileTypeLimit: {
      type: Array,
      default: () => ['jpg', 'jpeg', 'png', 'gif']
    }
  },
  data() {
    return {
      fileList: [],
      uploadPercentage: 0,
      status: 'warning'
    }
  },
  methods: {
    beforeUpload(file) {
      const isLtSize = file.size / 1024 / 1024 < this.fileSizeLimit
      const fileTypeArr = file.name.split('.')
      const fileType = fileTypeArr[fileTypeArr.length - 1].toLowerCase()
      const isFileType = this.fileTypeLimit.includes(fileType)
      if (!isLtSize) {
        this.$message.error(`上传图片不能超过 ${this.fileSizeLimit}MB!`)
        return false
      }
      if (!isFileType) {
        this.$message.error('上传图片格式必须是' + this.fileTypeLimit.join('、'))
        return false
      }
      return true
    },
    handleSuccess(response, file, fileList) {
      if (response.code !== '0') {
        this.$message.error('上传失败')
        return
      }
      const { data } = response
      if (data && data.length > 0) {
        data.forEach(item => {
          this.fileList.push({
            url: item.url,
            name: item.name
          })
        })
        this.status = 'success'
      }
    },
    handleProgress(event, file, fileList) {
      this.uploadPercentage = Math.floor(event.percent)
    },
    handleDelete(index) {
      this.fileList.splice(index, 1)
      this.$refs.upload.clearFiles()
      this.uploadPercentage = 0
      this.status = 'warning'
    }
  },
  watch: {
    fileList: {
      handler(val) {
        this.$emit('update:fileList', val)
      },
      deep: true
    }
  }
}
</script>

上述代码可以实现多张图片上传,预览已上传的多张图片,并提供删除功能。

自定义上传按钮

通过在上传图片组件内部增加一个插槽,我们可以实现上传按钮的样式自定义。下面的示例中,使用element-ui中的icon组件来渲染一个带图标的自定义上传按钮。

<template>
  <div>
    <el-upload
      class="upload-file"
      :action="uploadUrl"
      :show-file-list="false"
      :data="formData"
      :on-success="handleSuccess"
      :before-upload="beforeUpload"
      :on-progress="handleProgress"
      :multiple="true"
      ref="upload"
    >
      <slot name="upload-btn">
        <el-button
          size="medium"
          type="primary"
          :disabled="disabled"
        >
          <i class="el-icon-plus"></i>
          上传图片
        </el-button>
      </slot>
      <el-progress
        class="upload-progress"
        :percentage="uploadPercentage"
        :stroke-width="2"
        :color="customColor"
        :hide-info="true"
        :show-text="false"
        :status="status"
      ></el-progress>
    </el-upload>
    <div class="view-file-list" v-if="fileList && fileList.length > 0">
      <el-card
        shadow="hover"
        v-for="(file, index) in fileList"
        :key="file.url + index"
        class="view-card"
      >
        <img
          :src="file.url || file.preview"
          class="view-img"
        />
        <el-button
          size="small"
          type="danger"
          class="delete-btn"
          icon="el-icon-delete"
          @click.prevent="handleDelete(index)"
        ></el-button>
      </el-card>
    </div>
  </div>
</template>

<script>
export default {
  name: 'UploadImage',
  props: {
    uploadUrl: {
      type: String,
      required: true
    },
    formData: {
      type: Object,
      default: () => ({})
    },
    disabled: {
      type: Boolean,
      default: false
    },
    customColor: {
      type: String,
      default: ''
    },
    fileSizeLimit: {
      type: Number,
      default: 2
    },
    fileTypeLimit: {
      type: Array,
      default: () => ['jpg', 'jpeg', 'png', 'gif']
    }
  },
  data() {
    return {
      fileList: [],
      uploadPercentage: 0,
      status: 'warning'
    }
  },
  methods: {
    beforeUpload(file) {
      const isLtSize = file.size / 1024 / 1024 < this.fileSizeLimit
      const fileTypeArr = file.name.split('.')
      const fileType = fileTypeArr[fileTypeArr.length - 1].toLowerCase()
      const isFileType = this.fileTypeLimit.includes(fileType)
      if (!isLtSize) {
        this.$message.error(`上传图片不能超过 ${this.fileSizeLimit}MB!`)
        return false
      }
      if (!isFileType) {
        this.$message.error('上传图片格式必须是' + this.fileTypeLimit.join('、'))
        return false
      }
      return true
    },
    handleSuccess(response, file, fileList) {
      if (response.code !== '0') {
        this.$message.error('上传失败')
        return
      }
      const { data } = response
      if (data && data.length > 0) {
        data.forEach(item => {
          this.fileList.push({
            url: item.url,
            name: item.name
          })
        })
        this.status = 'success'
      }
    },
    handleProgress(event, file, fileList) {
      this.uploadPercentage = Math.floor(event.percent)
    },
    handleDelete(index) {
      this.fileList.splice(index, 1)
      this.$refs.upload.clearFiles()
      this.uploadPercentage = 0
      this.status = 'warning'
    }
  },
  watch: {
    fileList: {
      handler(val) {
        this.$emit('update:fileList', val)
      },
      deep: true
    }
  }
}
</script>

通过上面的示例说明,读者可以了解到我们如何封装一个上传图片组件,以及如何实现多图上传和自定义上传按钮。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue封装组件之上传图片组件 - Python技术站

(0)
上一篇 2023年6月25日
下一篇 2023年6月25日

相关文章

  • 基于spring同名bean覆盖问题的解决

    一、背景 在Spring IoC容器中,如果存在多个同名的bean,那么Spring IoC容器将会选择其中一个作为该类型的bean。但是,有时候我们需要覆盖和替换这些同名的bean。例如,我们可能需要在测试环境中使用一个模拟的bean,而在生产环境中使用真正的bean。本攻略将解决这个覆盖问题。 二、基于spring同名bean覆盖问题的解决方案 使用@P…

    other 2023年6月26日
    00
  • 笔记本开机出现两个用户名怎么删除一个?

    要删除一个在登录界面上出现的用户名,可以按照以下步骤进行操作: 在键盘上同时按下“Windows键 + R”键,打开运行对话框。 在运行对话框中输入“netplwiz”并点击“确定”按钮,打开“用户账户”窗口。 在“用户账户”窗口中,可以看到所有的用户账户。如果想要删除一个账户,请选中该账户并点击“移除”按钮。如果没有“移除”按钮,代表这个账户是系统默认管理…

    other 2023年6月27日
    00
  • Linux内核链表实现过程

    首先我们需要知道链表是什么。链表是一种数据结构,它由一系列节点组成,其中每个节点都包含一个指向下一个节点的指针。链表可以动态地添加或删除节点,使其具有灵活性。接着,我们来看看如何在Linux内核中实现链表。 实现步骤 以下是Linux内核中实现链表的步骤: 定义链表节点结构体,通常包含两个成员:指向下一个节点的指针和一个数据成员。 c struct list…

    other 2023年6月27日
    00
  • Jmeter 中 CSV 如何参数化测试数据并实现自动断言示例详解

    JMeter中参数化测试数据并实现自动断言的完整攻略 以下是使用JMeter实现参数化测试数据并实现自动断言的完整攻略: 步骤1:准备CSV文件 首先,您需要准备一个包含测试数据的CSV文件。该文件将包含您要使用的参数化数据。确保CSV文件的格式正确,并且每行数据对应一个测试用例。 步骤2:配置CSV数据集配置元件 在JMeter中,您可以使用CSV数据集配…

    other 2023年10月16日
    00
  • pycharm 使用anaconda为默认环境的操作

    要使用Anaconda为默认的Python环境,可以按照以下步骤操作: 步骤1:安装Anaconda 首先下载和安装Anaconda,可以从官网(https://www.anaconda.com/)下载安装包。 安装过程中需要勾选“Add Anaconda to my PATH environment variable”选项,这样Anaconda的路径就会被…

    other 2023年6月26日
    00
  • C语言基础指针详解教程

    当学习C语言的基础指针时,以下是一个完整的攻略,包括两个示例说明。 指针的基本概念 指针是C语言中的一个重要概念,它用于存储变量的内存地址。通过指针,我们可以直接访问和修改内存中的数据。下面是一些指针的基本概念: 声明指针:使用*符号来声明指针变量。例如,int *ptr;声明了一个指向整数的指针变量ptr。 获取变量地址:使用&运算符来获取变量的地…

    other 2023年8月15日
    00
  • delphi“div”、“mod”、“”除法运算符的区别与使用方法

    Delphi中div和mod除法运算符的区别与使用方法 Delphi是一种基于Pascal语言的面向对象编程语言,与其他编程语言一样,除法运算符也是一个常见的操作。除法运算符在Delphi中有三种常见的形式,分别是/(普通除法)、div(整数除法)和mod(取模运算符)。 底层实现 对于任何一种计算机语言中的除法运算符,其底层实现都是一样的。在计算机中,所有…

    其他 2023年3月29日
    00
  • 使用.netjustdecompile来反编译你的程序代码

    使用.netjustdecompile工具可以反编译.NET程序代码,以便查看程序的实现细节和进行代码分析。以下是关于使用.netjustdecompile的详细攻略: 步骤一:下载和安装.netjustdecompile 可以从官方网站下载.netjustdecompile工具,下载完成后进行安装。 步骤二:打开.netjustdecompile 打开.n…

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