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

yizhihongxing

下面我将详细讲解“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日

相关文章

  • Android 7.0行为变更 FileUriExposedException解决方法

    以下是使用标准的Markdown格式文本,详细讲解Android 7.0行为变更FileUriExposedException的解决方法的完整攻略: Android 7.0行为变更 FileUriExposedException解决方法 在Android 7.0及以上的版本中,引入了一项安全性改进,即禁止应用在使用file:// URI访问其他应用的私有文件…

    other 2023年10月14日
    00
  • sqlalchemy转json的几种常用方式

    SQLAlchemy转JSON的几种常用方式 在Web开发中,我们通常需要将从数据库中查询到的数据以JSON格式返回给客户端浏览器,这样便于前端开发使用。而在使用Python后台框架Flask和Django等时,查询数据的第一步就是使用ORM框架进行操作,其中SQLAlchemy是一种常用的ORM框架。 那么,如何使用SQLAlchemy将查询到的数据转换为…

    其他 2023年3月29日
    00
  • vue中使用postcss-px2rem的两种方法

    当我们在Vue项目中使用PostCSS-px2rem时,我们可以采用以下两种方法: 方法一:vue-cli-plugin-px2rem-auto vue-cli-plugin-px2rem-auto是一个Vue CLI插件,可以帮助我们轻松地将px转换为rem,并支持vw、vh等单位。 步骤如下: 安装插件 npm install vue-cli-plugi…

    other 2023年6月27日
    00
  • taskset命令详解

    taskset命令详解 在Linux操作系统中,taskset命令可以帮助我们将进程绑定到特定的CPU核心上。本文将详细介绍taskset命令的用法和相关注意事项。 命令语法 taskset [options] [mask] pid 其中,options代表命令选项,mask代表进程的CPU掩码,pid代表需要进行操作的进程ID。 CPU掩码 CPU掩码是一…

    其他 2023年3月28日
    00
  • 浅谈python模块的导入操作

    浅谈python模块的导入操作 在Python中,模块是一种组织代码的方式,可将代码拆分为多个文件,方便复用和维护。Python标准库中以及第三方库中都提供了大量具有各种功能的模块。在使用Python时,我们通常需要使用一些已经存在的模块。而要使用这些模块,我们需要进行导入操作,本文将为大家简要介绍Python中常用的模块导入操作。 导入模块 在Python…

    其他 2023年3月28日
    00
  • QQ、TM无法启动,提示“应用程序无法启动,因为应用程序的并行配置不正确”的解决方法

    为了解决QQ、TM无法启动,提示“应用程序无法启动,因为应用程序的并行配置不正确”的问题,我们可以按照下面的步骤进行操作。 初步检查 首先,我们需要检查自己的电脑是否完全符合QQ、TM的系统要求。例如,QQ和TM需要在Windows 7或更高版本的操作系统上运行。同时,你需要确保你的电脑上已经安装了所有必要的软件和组件,例如.NET Framework。 重…

    other 2023年6月25日
    00
  • 华为mate8怎么刷机 华为mate8两种刷机教程

    华为mate8怎么刷机 前置条件 在进行华为mate8刷机前,请务必做好以下几点准备: 1.备份好手机中的重要数据,并将备份文件存储到安全的地方; 2.确保手机电量充足,在刷机过程中不要断电; 3.下载并安装好适用于华为mate8的刷机工具及刷机包; 4.了解所使用刷机工具和刷机包的适用版本,避免不必要的麻烦和损失。 刷机方法一:使用华为官方线刷工具 1.首…

    other 2023年6月27日
    00
  • 罪恶装备Xrd SIGN停止工作黑屏等问题的解决方法

    罪恶装备Xrd SIGN停止工作黑屏等问题的解决方法 在玩《罪恶装备Xrd SIGN》时,有可能会遇到游戏停止工作、黑屏等问题,这些问题可能是由于多种原因引起的。下面我们将对这些问题进行详细的解决方案。 问题一:游戏停止工作 解决方法: 确保您的电脑系统是兼容罪恶装备Xrd SIGN的,且满足游戏运行的最低配置要求。 关闭安装在计算机上的任何游戏加速器、杀毒…

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