[前端工程化 - 组件封装]图片上传组件

前言

大家好,我是辉夜真是太可爱啦,这是我即将最新开启的组件封装或基于组件库二次封装系列,代码均以 vue2 为例,组件库以 vant 为栗子

组件的封装在工作中使用的用处还是很大的,主要体现在维护的方便,可以将所有固定的代码抽到同一个组件中进行统一管理。

封装目的

这次是实现的是图片上传的功能,由于 vant 组件的 uploader 组件的 v-model 设计不太合理。

一般来说,正常单张图片的值是一个 String ,例如 https://xxxx.jpg

然后一串图片是一个 Array ,例如 ['https://xxxx.jpg' , 'https://xxxx.jpg']

然后我们仅通过一个 v-model 即可绑定这个值,无需对图片上传之后值的更新,图片删除之后值的清空,或者是默认值的渲染再做多余的管理,可以大大的提升图片相关功能的开发效率。

后期还可以配合写一个 form 组件,使用 json 生成 form 表单。

Props

  • v-model 绑定的图片的值
  • max-count 绑定的最大值,1为单张图,大于1为列表
  • tips 文件上传提示语

Slot

  • defautl 默认插槽,用于修改图片上传的控件

开始封装

先书写 template 板块,关于插槽内的图片上传框的样式请自行修改。

html 复制代码
<template>
  <div class="image-uploader-component-main-box">
    <van-uploader
      :after-read="afterRead"
      :max-size="1024 * 1024 * 10"
      @delete="deleteFile"
      v-model="fileList"
      :max-count="maxCount"
      accept="image/png,image/jpeg,image/jpg"
    >
      <slot>
        <div class="upload-box">
          <span>图片上传</span>
        </div>
      </slot>
    </van-uploader>
  </div>
</template>

接下来,就是封装 js 的部分,由于fileList的格式是固定的,所以接下来需要用一个currentValue来进行绑定,fileList的数组,在初次渲染的时候,需要将currentValue中的值赋值给fileList,这样子才能保持两边数组的同步。

当然,uploadImage 图片上传的调用行为,请自行修改。

javascript 复制代码
<script>
export default {
  name: 'ImageUploader',

  props: {
    value: {
      type: [Array, String],
      default: '',
    },
    maxCount: {
      type: Number,
      default: 1,
    },
  },

  data() {
    return {
      currentValue: this.value,
      fileList: [],
      isInit: false, // 将一开始的默认值赋值给 fileList
    }
  },

  watch: {
    value: {
      handler(newValue) {
        if (!this.isInit) {
          if (this.maxCount === 1) {
            this.fileList = [
              {
                url: newValue,
                status: 'success',
                message: '上传成功',
              },
            ]
          } else {
            newValue.forEach((item) => {
              this.fileList.push({
                url: item,
                status: 'success',
                message: '上传成功',
              })
            })
          }
        }
        this.currentValue = newValue
      },
    },
  },

  methods: {
    afterRead(file) {
      this.isInit = true
      file.status = 'uploading'
      file.message = '上传中...'
      const formData = new FormData()
      formData.append('file', file.file)
      uploadImage(formData)
        .then((res) => {
          if (res.url) {
            file.status = 'success'
            file.message = '上传成功'
            file.url = res // FIXME: 这里上传不做全地址处理了
            if (this.maxCount === 1) {
              this.currentValue = res.url
            } else {
              this.currentValue.push(res.url)
            }
            this.$emit('input', this.currentValue)
          } else {
            file.status = 'failed'
            file.message = '上传失败'
            this.$toast.fail(res.error)
          }
        })
        .catch(() => {
          file.status = 'failed'
          file.message = '上传失败'
        })
    },

    deleteFile(file) {
      if (this.maxCount === 1) {
        this.currentValue = ''
      } else {
        this.currentValue.splice(
          this.currentValue.findIndex((x) => x === file.url),
          1
        )
      }
      this.$emit('input', this.currentValue)
    },
  },
}
</script>

至于另外别的 API,此处不再做多余的赘述,仅仅搬运下即可。

组件使用

  • 单个使用
javascript 复制代码
<ImageUploader v-model="imgUrl"></ImageUploader>

data() {
  return {
    imgUrl: ''
  }
},
  • 多个使用
ruby 复制代码
<ImageUploader v-model="imgList" :max-count="5"></ImageUploader>

data() {
  return {
    imgList: []
  }
},
相关推荐
顾平安1 小时前
Promise/A+ 规范 - 中文版本
前端
聚名网1 小时前
域名和服务器是什么?域名和服务器是什么关系?
服务器·前端
桃园码工1 小时前
4-Gin HTML 模板渲染 --[Gin 框架入门精讲与实战案例]
前端·html·gin·模板渲染
沈剑心1 小时前
如何在鸿蒙系统上实现「沉浸式」页面?
前端·harmonyos
一棵开花的树,枝芽无限靠近你1 小时前
【PPTist】组件结构设计、主题切换
前端·笔记·学习·编辑器
m0_748237052 小时前
Chrome 关闭自动添加https
前端·chrome
prall2 小时前
实战小技巧:下划线转驼峰篇
前端·typescript
开心工作室_kaic2 小时前
springboot476基于vue篮球联盟管理系统(论文+源码)_kaic
前端·javascript·vue.js
川石教育2 小时前
Vue前端开发-缓存优化
前端·javascript·vue.js·缓存·前端框架·vue·数据缓存
搏博2 小时前
使用Vue创建前后端分离项目的过程(前端部分)
前端·javascript·vue.js