美文网首页
Ant Design Vue - upload公共组件将封装

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

作者: 爱吃豆包 | 来源:发表于2021-10-24 18:14 被阅读0次

    因为 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)转化为控件的值!
    如果不能理解这句话请看看 双向绑定的原理以及实现!

    效果:

    上传结果 提交的值

    相关文章

      网友评论

          本文标题:Ant Design Vue - upload公共组件将封装

          本文链接:https://www.haomeiwen.com/subject/xazraltx.html