寫在前面(說幾句廢話)
ant design是一套非常優(yōu)秀的組件庫惨篱,其中有react版本和vue版本砸讳,二者除了語法 上的差異界牡,使用思想基本大同小異,其中ant design 的Form
組件又是使用頻率非常高的組件常遂,但往往挽荠,我們在做一些復雜功能的時候,通常需要對其進行二次封裝漠另,于是我就遇到了這樣的問題
“React和Vue都是作為單向數(shù)據(jù)流的框架跃赚,我們通常是使用‘父傳子,子調父’的形式來做組件通信的纬傲,對我封裝的表單組件叹括,怎么才能將子組件的值暴露在父組件中供父組件的Form
方法捕獲,并同意操作值或者校驗呢汁雷?摔竿?”
這個問題困擾了我很久,以至于很長一段時間我都是通過回調函數(shù)的形式來和父組件通信的继低,即,父組件傳一個操作Form的方法到子組件柴底,子組件在完成特定的事件后,調用這個方法狐树。但這樣用起來鸿脓,我們還得多傳一個回調函數(shù),并且在表單統(tǒng)一校驗和取值方面也不行在塔,但是沒辦法拨黔,于是,他像一根刺一樣埋在了我心里贺待,我總感覺不能和原組件使用方法相同的封裝用起來很鬧心零截。
一個偶然的機會,我發(fā)現(xiàn)瞻润,原來我沒有深刻體會到官方文檔中的這句話
當年的我還是一個小白绍撞,面對復雜的開發(fā)得院,我對這句話的認識只是固定在了現(xiàn)有組件的上面,包括他的
value
非洲,defaultevalue
等,而忽略了他對于自定義組件封裝的重要作用楼誓,真是這句話,真正解決了子組件像父組件回傳值的問題。我們不再使用callback的形式了帕识!好,下面開始進入正題肮疗。為盡可能解決大家遇到的問題伪货,這邊文章,我將分別使用React和Vue來實現(xiàn)一些功能碱呼,供大家參考
Antd中表單封裝回傳值至父組件
本文不管是antd4.x還是3.x還是ant design vue都適用巍举,這里我使用的是react版本的3.x。
對于上面官網(wǎng)的那句話懊悯,現(xiàn)在應該有一個更明確的理解炭分,要想我們的組件可以搭配Form組件使用,并和原生組件用法相同捧毛,我們的組件需要遵循以下幾點
- 提供受控屬性
value
或其它與valuePropName
的值同名的屬性呀忧。- 提供
onChange
事件或trigger
的值同名的事件- 支持 ref:
- React@16.3.0 之前只有 Class 組件支持。
- React@16.3.0 及之后可以通過forwardRef添加 ref 支持
- Vue中始終都支持ref
下面我們來實踐以下如何遵循上面的幾條規(guī)定
自定義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)
父組件就是一個常規(guī)的對Antd表單項的使用泞辐,主要內(nèi)容是對自定義表單的取值和校驗以及對其設值咐吼。下面是子組件封裝方法
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)
我們沒有做太復雜的封裝,主要目的是為了演示如何遵循正確的規(guī)則去配合Form
組件的使用厢塘。上面的組件有以下幾點特點
有value屬性受控
提供 onChange 事件,這里是最重要的一點俗冻,可以看到代碼中有Input組件自帶的onChange事件迄薄,有從props中取的onChange事件,那么規(guī)則中的onChange事件指的是哪一個呢讥蔽?答案是props中的onChange冶伞,這一步很管家
支持ref,因為class組件本身支持ref這里我特意用函數(shù)組件做實例响禽,看其如何用
這次我們再來對上面那所謂的規(guī)律做總結
通過getFieldDecorator
包裝后,組件自帶value屬性芋类,或者指定的valuePropName屬性,我們可以通過這個特點 來設置組件的值胖喳,達到父組件驅動父組件的目的
通過getFieldDecorator
包裝后贮竟,組件自帶onChange屬性咕别,我們可以通過調用這個方法,將值回傳給父組件這是相當關鍵的一步顷级,也是我一直忽略了的一點
自定義Upload組件(Vue版本)
上面我們用react版本的antd演示了如何做正確的做表單項封裝弓颈,對于需要遵循的規(guī)定删掀,也是用了比較常規(guī)的value和onChange,下面我們來使用vue版本來演示更復雜的使用方式披泪,思想和上面的簡單實例一樣。
首先是父組件
<a-form :form="form">
<a-form-item label="自定義上傳組件">
<myCom v-decorator="['uploadCom', {trigger: 'uploadDone', valuePropName: 'fileList'}]"/>
</a-form-item>
</a-form>
父組件中控硼,我們設置了trigger
和valuePropName
卡乾,即規(guī)則中的第一條和第二條。二者都是自定義字段幔妨。其中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>
上面為官網(wǎng)完整demo陪踩,大家在實際項目中可根據(jù)情況封裝更復雜的組件悉抵,集中上面的代碼關鍵點在以下
props: { fileList: Array // 因為通過v-decorator包裝后會自動注入valuePropName屬性 }
handleChange (info) { this.$listeners.uploadDone(info.fileList) // 這里我是本地基跑,所以將該方法放在了一開始,可根據(jù)需求決定放在哪里媳否,一般是放到文件上傳完成后
我們通過this.$listeners.uploadDone
來將值回傳,從而保證父組件可以通過Form方法獲取值力图。說實話我也是找了半天才從this.$listeners
里找到uploadDone
,其中uploadDone
是我們在父組件自定義的trigger
,這里為了講解我故意設置了一下掺逼,不設置的話,取默認的onChange
即可赘那。
關于自定義校驗
通過上面正確的封裝后氯质,我們已經(jīng)可以通過Form來獲取組件暴露的值了,這樣我們在做一些自定義檢驗的時候拱礁,就可以使用validator
做自定義校驗了
總結
通過上面的封裝,我們就可以正常的像用原生antd組件那樣使用自定義的組件了吴超,不管你是react用戶還是vue用戶鸯乃,思想都是一樣,一定要記住上面的三條規(guī)范飒责,同時頁要反思赘娄,文檔要深刻理解哦好了,去試試吧本人已親測有效