踩坑日记:关于antd表单封装回传值至父组件的问题

gogogo.jpg

写在前面(说几句废话)

ant design是一套非常优秀的组件库,其中有react版本和vue版本,二者除了语法 上的差异,使用思想基本大同小异,其中ant design 的Form组件又是使用频率非常高的组件,但往往,我们在做一些复杂功能的时候,通常需要对其进行二次封装,于是我就遇到了这样的问题
“React和Vue都是作为单向数据流的框架,我们通常是使用‘父传子,子调父’的形式来做组件通信的,对我封装的表单组件,怎么才能将子组件的值暴露在父组件中供父组件的Form方法捕获,并同意操作值或者校验呢??”
这个问题困扰了我很久,以至于很长一段时间我都是通过回调函数的形式来和父组件通信的,即,父组件传一个操作Form的方法到子组件,子组件在完成特定的事件后,调用这个方法。但这样用起来,我们还得多传一个回调函数,并且在表单统一校验和取值方面也不行,但是没办法,于是,他像一根刺一样埋在了我心里,我总感觉不能和原组件使用方法相同的封装用起来很闹心。
一个偶然的机会,我发现,原来我没有深刻体会到官方文档中的这句话

form.PNG

当年的我还是一个小白,面对复杂的开发,我对这句话的认识只是固定在了现有组件的上面,包括他的valuedefaultevalue等,而忽略了他对于自定义组件封装的重要作用,真是这句话,真正解决了子组件像父组件回传值的问题。我们不再使用callback的形式了!好,下面开始进入正题。
为尽可能解决大家遇到的问题,这边文章,我将分别使用React和Vue来实现一些功能,供大家参考

Antd中表单封装回传值至父组件

本文不管是antd4.x还是3.x还是ant design vue都适用,这里我使用的是react版本的3.x。
对于上面官网的那句话,现在应该有一个更明确的理解,要想我们的组件可以搭配Form组件使用,并和原生组件用法相同,我们的组件需要遵循以下几点

  • 提供受控属性 value 或其它与 valuePropName的值同名的属性。
  • 提供 onChange 事件或 trigger 的值同名的事件
  • 支持 ref:
    • React@16.3.0 之前只有 Class 组件支持。
    • React@16.3.0 及之后可以通过forwardRef添加 ref 支持
    • Vue中始终都支持ref

下面我们来实践以下如何遵循上面的几条规定

自定义Input组件(React版本)

这里先用react版来做第一个实验,我将组件做了下面的封装和使用

父组件中

import React from 'react'
import CustomInput from './components/CustomInput '

const FormItem = Form.Item;
const Parent= props => {
    const { getFieldDecorator } = props.form
    const getValue = () => {
        props.form.validateFields((err, val) => {
            if(!err) {
                console.log(val)
            }
        })
    }
    const setValue = () => {
        props.form.setFieldsValue({title: '909090'})
    }
    return (
        <>
            <Button onClick={getValue}>获取表单</Button>
            <Button onClick={setValue}>给表单赋值</Button>
            <Form>
                <FormItem label="标题">
                    {getFieldDecorator('title', {
                    })(<CustomInput />)}
                </FormItem>
            </Form>
        </>
    )
}
export default Form.create()(Parent)

父组件就是一个常规的对Antd表单项的使用,主要内容是对自定义表单的取值和校验以及对其设值。下面是子组件封装方法

import React from 'react'
import { Input } from 'antd'

const PriceInput = (props, ref) => {
    const inputChange = e => {
        const { onChange } = props
        onChange(e.target.value)
    }
    return (<Input ref={ref} value={props.value} onChange={inputChange}/>)
}
export default React.forwardRef(PriceInput)

我们没有做太复杂的封装,主要目的是为了演示如何遵循正确的规则去配合Form组件的使用。上面的组件有以下几点特点

  • 有value属性受控

  • 提供 onChange 事件,这里是最重要的一点,可以看到代码中有Input组件自带的onChange事件,有从props中取的onChange事件,那么规则中的onChange事件指的是哪一个呢?答案是props中的onChange,这一步很管家

  • 支持ref,因为class组件本身支持ref这里我特意用函数组件做实例,看其如何用

这次我们再来对上面那所谓的规律做总结

通过getFieldDecorator包装后,组件自带value属性,或者指定的valuePropName属性,我们可以通过这个特点 来设置组件的值,达到父组件驱动父组件的目的

通过getFieldDecorator包装后,组件自带onChange属性,我们可以通过调用这个方法,将值回传给父组件这是相当关键的一步,也是我一直忽略了的一点

自定义Upload组件(Vue版本)

上面我们用react版本的antd演示了如何做正确的做表单项封装,对于需要遵循的规定,也是用了比较常规的value和onChange,下面我们来使用vue版本来演示更复杂的使用方式,思想和上面的简单实例一样。

首先是父组件

<a-form :form="form">
  <a-form-item label="自定义上传组件">
   <myCom v-decorator="['uploadCom', {trigger: 'uploadDone', valuePropName: 'fileList'}]"/>
  </a-form-item>
</a-form>

父组件中,我们设置了triggervaluePropName,即规则中的第一条和第二条。二者都是自定义字段。其中trigger是我们回传值的时候要调用的方法,valuePropName是我们要注入到子组件中的属性。
看子组件封装

<template>
  <a-upload
    name="file"
    :multiple="true"
    action="https://www.mocky.io/v2/5cc8019d300000980a055e76"
    :headers="headers"
    @change="handleChange"
    :fileList="fileList"
  >
    <a-button> <a-icon type="upload" /> Click to Upload </a-button>
  </a-upload>
</template>
<script>
export default {
  data () {
    return {
      headers: {
        authorization: 'authorization-text'
      }
    }
  },
  props: {
    fileList: Array
  },
  methods: {
    handleChange (info) {
      this.$listeners.uploadDone(info.fileList)
      if (info.file.status !== 'uploading') {
        console.log(info.file, info.fileList)
      }
      if (info.file.status === 'done') {
        this.$message.success(`${info.file.name} file uploaded successfully`)
      } else if (info.file.status === 'error') {
        this.$message.error(`${info.file.name} file upload failed.`)
      }
    }
  }
}
</script>

上面为官网完整demo,大家在实际项目中可根据情况封装更复杂的组件,集中上面的代码关键点在以下

  • props: {
      fileList: Array // 因为通过v-decorator包装后会自动注入valuePropName属性
    }
    
    
  • handleChange (info) {
      this.$listeners.uploadDone(info.fileList) // 这里我是本地,所以将该方法放在了一开始,可根据需求决定放在哪里,一般是放到文件上传完成后
    

我们通过this.$listeners.uploadDone来将值回传,从而保证父组件可以通过Form方法获取值。说实话我也是找了半天才从this.$listeners里找到uploadDone,其中uploadDone是我们在父组件自定义的trigger,这里为了讲解我故意设置了一下,不设置的话,取默认的onChange即可。

关于自定义校验

通过上面正确的封装后,我们已经可以通过Form来获取组件暴露的值了,这样我们在做一些自定义检验的时候,就可以使用validator做自定义校验了

总结

通过上面的封装,我们就可以正常的像用原生antd组件那样使用自定义的组件了,不管你是react用户还是vue用户,思想都是一样,一定要记住上面的三条规范,同时页要反思,文档要深刻理解哦好了,去试试吧本人已亲测有效

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容