Ant Design Vue - upload公共组件将封装

因为 elment-ui 好像没有维护了, 就采用了 Ant Design Vue 组件库。

因为项目里面好多地方使用了 Upload(a-upload) 上传组件,所以就进行二次封装(比如上传路径等等)!
并且交付 Form(a-form) 组件进行托管

老实说交付 Form(a-form) 自动接管这里的坑真大, 百度了好久没有解决方案(都没有进行二次封装)

先看 Form(a-form) 组件的一段描述

经过 getFieldDecoratorv-decorator 包装的控件,表单控件会自动添加 value(或 valuePropName 指定的其他属性) onChange(或 trigger 指定的其他属性),数据同步将被 Form(a-form) 接管,这会导致以下结果:

  • 你不再需要也不应该用 onChange 来做同步,但还是可以继续监听 onChange 等事件。
  • 你不能用控件的 value defaultValue 等属性来设置表单域的值,默认值可以用 getFieldDecoratorv-decorator 里的 initialValue
  • 你不应该用 v-model,可以使用 this.form.setFieldsValue 来动态改变表单值。

这里坑就坑在 onChange 的这段描述,因为之前一直在写React也是使用 Ant Design 进行二次组件封装时候写的 this.props.onChange(xxx), 所以Vue这边上传成功后发送事件我就写成了 this.$emit("onChange", info.file.response.data) 导致 Form(a-form) 一直接管不到!

也看了 Vue 官网的自定义组件:

一个组件上的 v-model 默认会利用名为 value 的 prop 和名为 input 的事件,但是像单选框、复选框等类型的输入控件可能会将 value attribute 用于不同的目的

所以我又改成了这样: this.$emit("input", info.file.response.data) 还是不行, Form(a-form) 也接管不到!

于是想到了 Vue 在接受事件处理的习惯写法上 @change => onChange ,所以就改成了 this.$emit("change", info.file.response.data),就成功了。。。

至于为什么 Ant Design Vue 没有使用 input 事件的原因,应该是通过了自定义组件中的 model 属性进行了修改,以达到和 React 版本的 Ant Design 组件库的API一致。
Ant Design Vue 还出了一个 v-modelFormModel 的版本的From表单,有时间可以看看!

完整代码(记得看到最下面如何使用):

<template>
            <a-upload
              name="file"
              list-type="picture-card"
              class="avatar-uploader"
              :withCredentials="true"
              :show-upload-list="false"
              :action="url"
              :before-upload="beforeUpload"
              @change="handleChange"
              :headers="headers"
            >
              <img class="pre-img" v-if="value" :src="value" alt="avatar" />
              <div v-else>
                <a-icon :type="loading ? 'loading' : 'plus'" />
                <div class="ant-upload-text">
                  Upload
                </div>
              </div>
            </a-upload>
</template>

<script>
import { getToken } from '@/utils/localStorage'

// 图片文件上传
export default {
    name: 'upload',
    props: {
        value: {
            type: String,
            default: ''
        },
    },
    data() {
       return {
            // 上传请求地址
            url: process.env.VUE_APP_IMG_UPLOAD_URL,
            loading: false,
            headers: {
              Authorization: `bearer ${getToken()}`
            }
       }
    },
    methods: {
       handleChange(info) {
         console.log(info)
        if (info.file.status === 'uploading') {
          this.loading = true;
          return;
        }
        if (info.file.status === 'done') { // 上传成功会有有一个 done 状态标识成功
          this.loading = false;
          this.imageUrl = info.file.response.data;
          // 发送事件
          // 重点来了这里必须是 change 事件
          this.$emit("change", info.file.response.data);
        }
      },
      beforeUpload(file) {
        const isJpgOrPng = file.type === 'image/jpeg' || file.type === 'image/png';
        if (!isJpgOrPng) {
          this.$message.error('You can only upload JPG file!');
        }
        const isLt2M = file.size / 1024 / 1024 < 2;
        if (!isLt2M) {
          this.$message.error('Image must smaller than 2MB!');
        }
        return isJpgOrPng && isLt2M;
      },
    }
}
</script>

<style>
.avatar-uploader > .ant-upload, .pre-img {
  width: 128px;
  height: 128px;
}
.ant-upload-select-picture-card i {
  font-size: 32px;
  color: #999;
}

.ant-upload-select-picture-card .ant-upload-text {
  margin-top: 8px;
  color: #666;
}
</style>
<style lang="less" scoped>

</style>

如何使用:

// 引入定义好的组件
import ImgUpload from '@/components/upload/index.vue'
export default {
  // 并且在这里注册一下
  components: { ImgUpload },

    ...省略其他代码
}
<a-form :form="form" :label-col="{ span: 3 }" :wrapper-col="{ span: 8 }" @submit="handleSubmit">
    ...省略其他组件
    <a-form-item label="公司Logo">
         <img-upload v-decorator="['logo', { getValueFromEvent: normFile, initialValue: '' }]"/>
   </a-form-item>
</a-form>

// 函数,Form 获取结果
normFile(e) {
        console.log('Upload event:', e);
        return e;
 },

重点来了 getValueFromEventForm(a-form) 接管后, 可以把 onChange 事件的参数(如 event)转化为控件的值!
如果不能理解这句话请看看 双向绑定的原理以及实现!

效果:

上传结果
提交的值
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。