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日

相关文章

  • 如何在yml配置文件中使用中文注解

    如果需要在yml配置文件中添加中文注解,可以按照以下步骤进行: 确保yml文件开头的标记为—。在这个标记下方添加注解即可。 在需要注解的行前面添加’#’符号,然后在’#’后面添加中文注解。 例如,下面是一个基本的yml配置文件,我们需要对其中的一些参数进行注解,以便其他人易于理解: — name: my-app server: port: 8080 …

    other 2023年6月25日
    00
  • ubuntu16.04下vim的安装与配置

    下面是“Ubuntu 16.04下Vim的安装与配置的完整攻略”,包括安装、配置和两个示例说明。 安装 在 Ubuntu 16.04 中,可以使用以下命令安装 Vim: sudo apt-get update sudo apt-get install vim 配置 在 Ubuntu 16.04 中,可以按照以下步骤配置 Vim: 打开终端并输入以下命令: v…

    other 2023年5月5日
    00
  • WPS 插件和鼠标右键的精妙配合

    标题:WPS插件和鼠标右键的精妙配合攻略 正文: WPS插件可以极大地提高我们的工作效率,而鼠标右键也是我们经常使用的快捷键之一。在WPS中,将插件与鼠标右键配合起来,可以使我们的日常工作更加高效便捷。 一、安装WPS插件 要实现WPS插件的右键菜单功能,首先需要安装对应的插件。我们以WPS文字为例,步骤如下: 打开WPS文字软件,点击“插件”菜单下的“插件…

    other 2023年6月27日
    00
  • 用存储过程、GetRows()、抽取10万条数据的速度测试

    很抱歉,作为文本模型,我无法以标准的markdown格式回答您的问题。但是,我可以为您提供一份详细的攻略,包含使用存储过程、GetRows()和抽取10万条数据的速度测试的步骤和示例说明。 使用存储过程 首先,创建一个存储过程,用于抽取数据。例如,创建一个名为GetEmployees的存储过程,用于从Employees表中抽取数据。 CREATE PROCE…

    other 2023年10月17日
    00
  • Hbuilder开发HTML5 APP之创建子页面

    Hbuilder开发HTML5 APP之创建子页面 在Hbuilder中开发HTML5 APP,创建多个页面是必不可少的。创建多个子页面可以更好地组织你的APP结构,丰富你的APP功能,提升用户体验。在本篇文章中,我们将提供详细的步骤指导,教你如何创建一个子页面。 第一步:创建父页面 在Hbuilder中创建父页面相对简单。打开Hbuilder,选择项目文件…

    其他 2023年3月28日
    00
  • 微信小程序 生命周期详解

    关于微信小程序的生命周期,我们可以分为两大类: 应用生命周期 页面生命周期 接下来我将详细介绍这两类生命周期的每个阶段以及相关方法的作用。 应用生命周期 应用生命周期指的是整个小程序的生命周期。应用生命周期的函数在 app.js 中定义。 onLaunch 当小程序初次启动的时候,会触发 onLaunch 函数。该函数在小程序生命周期内仅会被触发一次。该函数…

    other 2023年6月27日
    00
  • 在MySQL字段中使用逗号分隔符的方法分享

    下面就详细讲解一下在MySQL字段中使用逗号分隔符的方法。 一、为什么要使用逗号分隔符 在MySQL中,我们经常需要处理含有多个元素的字段数据,如标签、类别、权限、ID等。如果直接将这些元素存放在一列中,对于后续的查询和处理会很麻烦,影响数据库的性能。此时,我们可以使用逗号分隔符来将多个元素分开存储,这样能够有效提高查询效率,同时也方便了数据的处理和维护。 …

    other 2023年6月25日
    00
  • C语言中斐波那契数列的三种实现方式(递归、循环、矩阵)

    C语言中斐波那契数列的三种实现方式(递归、循环、矩阵) 斐波那契数列是指数列:1、1、2、3、5、8、13、21、…… 在数学上,斐波那契数列是以递归的方法来定义的,首两项为 1,之后每一项都是其前两项之和,即:F(1) = 1, F(2) = 1F(n) = F(n-1) + F(n-2) , n > 2 递归实现 递归是最贴近人类思维的一种算法实现…

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