parent
69a9649e92
commit
91251798b2
|
@ -0,0 +1,7 @@
|
|||
export default {
|
||||
// just for tag
|
||||
install: (Vue, options) => {
|
||||
Vue.directive('decorator', {
|
||||
})
|
||||
},
|
||||
}
|
|
@ -49,7 +49,7 @@ const getSlots = (ele) => {
|
|||
if (ele.$vnode) {
|
||||
componentOptions = ele.$vnode.componentOptions || {}
|
||||
}
|
||||
const children = componentOptions.children || []
|
||||
const children = ele.children || componentOptions.children || []
|
||||
const slots = {}
|
||||
children.forEach(child => {
|
||||
const name = (child.data && child.data.slot) || 'default'
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import PropTypes from '../_util/vue-types'
|
||||
import classNames from 'classnames'
|
||||
import Vue from 'vue'
|
||||
import isRegExp from 'lodash/isRegExp'
|
||||
import warning from '../_util/warning'
|
||||
import createDOMForm from '../vc-form/src/createDOMForm'
|
||||
import createFormField from '../vc-form/src/createFormField'
|
||||
import FormItem from './FormItem'
|
||||
|
@ -54,7 +56,7 @@ export const WrappedFormUtils = {
|
|||
|
||||
export const FormProps = {
|
||||
layout: PropTypes.oneOf(['horizontal', 'inline', 'vertical']),
|
||||
form: PropTypes.shape(WrappedFormUtils).loose,
|
||||
form: PropTypes.object,
|
||||
// onSubmit: React.FormEventHandler<any>;
|
||||
prefixCls: PropTypes.string,
|
||||
hideRequiredMark: PropTypes.bool,
|
||||
|
@ -110,29 +112,13 @@ export const ValidationRule = {
|
|||
// validateFirst?: boolean;
|
||||
// };
|
||||
|
||||
export default {
|
||||
const Form = {
|
||||
name: 'AForm',
|
||||
props: initDefaultProps(FormProps, {
|
||||
prefixCls: 'ant-form',
|
||||
layout: 'horizontal',
|
||||
hideRequiredMark: false,
|
||||
}),
|
||||
// static defaultProps = {
|
||||
// prefixCls: 'ant-form',
|
||||
// layout: 'horizontal',
|
||||
// hideRequiredMark: false,
|
||||
// onSubmit (e) {
|
||||
// e.preventDefault()
|
||||
// },
|
||||
// };
|
||||
|
||||
// static propTypes = {
|
||||
// prefixCls: PropTypes.string,
|
||||
// layout: PropTypes.oneOf(['horizontal', 'inline', 'vertical']),
|
||||
// children: PropTypes.any,
|
||||
// onSubmit: PropTypes.func,
|
||||
// hideRequiredMark: PropTypes.bool,
|
||||
// };
|
||||
|
||||
Item: FormItem,
|
||||
|
||||
|
@ -146,11 +132,19 @@ export default {
|
|||
fieldDataProp: FIELD_DATA_PROP,
|
||||
})
|
||||
},
|
||||
createForm (context, options = {}) {
|
||||
return new Vue(Form.create({ ...options, templateContext: context })())
|
||||
},
|
||||
provide () {
|
||||
return {
|
||||
FormProps: this.$props,
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
form () {
|
||||
this.$forceUpdate()
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
onSubmit (e) {
|
||||
const { $listeners } = this
|
||||
|
@ -174,6 +168,10 @@ export default {
|
|||
[`${prefixCls}-hide-required-mark`]: hideRequiredMark,
|
||||
})
|
||||
if (autoFormCreate) {
|
||||
warning(
|
||||
false,
|
||||
'`autoFormCreate` is deprecated. please use `form` instead.'
|
||||
)
|
||||
const DomForm = this.DomForm || createDOMForm({
|
||||
fieldNameProp: 'id',
|
||||
...options,
|
||||
|
@ -214,3 +212,5 @@ export default {
|
|||
return <form onSubmit={onSubmit} class={formClassName}>{$slots.default}</form>
|
||||
},
|
||||
}
|
||||
|
||||
export default Form
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
import intersperse from 'intersperse'
|
||||
import PropTypes from '../_util/vue-types'
|
||||
import classNames from 'classnames'
|
||||
import find from 'lodash/find'
|
||||
import Row from '../grid/Row'
|
||||
import Col, { ColProps } from '../grid/Col'
|
||||
import warning from '../_util/warning'
|
||||
import { FIELD_META_PROP, FIELD_DATA_PROP } from './constants'
|
||||
import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, getSlots, isValidElement } from '../_util/props-util'
|
||||
import { initDefaultProps, getComponentFromProp, filterEmpty, getSlotOptions, isValidElement, getSlots } from '../_util/props-util'
|
||||
import getTransitionProps from '../_util/getTransitionProps'
|
||||
import BaseMixin from '../_util/BaseMixin'
|
||||
import { cloneElement } from '../_util/vnode'
|
||||
import { cloneElement, cloneVNodes } from '../_util/vnode'
|
||||
export const FormItemProps = {
|
||||
id: PropTypes.string,
|
||||
prefixCls: PropTypes.string,
|
||||
|
@ -47,6 +48,10 @@ export default {
|
|||
'`Form.Item` cannot generate `validateStatus` and `help` automatically, ' +
|
||||
'while there are more than one `getFieldDecorator` in it.',
|
||||
)
|
||||
warning(
|
||||
!this.fieldDecoratorId,
|
||||
'`fieldDecoratorId` is deprecated. please use `v-decorator={id, options}` instead.'
|
||||
)
|
||||
},
|
||||
methods: {
|
||||
getHelpMessage () {
|
||||
|
@ -81,11 +86,8 @@ export default {
|
|||
if (getSlotOptions(child).__ANT_FORM_ITEM) {
|
||||
continue
|
||||
}
|
||||
const attrs = child.data && child.data.attrs
|
||||
if (!attrs) {
|
||||
continue
|
||||
}
|
||||
const slots = getSlots(child)
|
||||
const attrs = child.data && child.data.attrs || {}
|
||||
if (FIELD_META_PROP in attrs) { // And means FIELD_DATA_PROP in child.props, too.
|
||||
controls.push(child)
|
||||
} else if (slots.default) {
|
||||
|
@ -339,11 +341,34 @@ export default {
|
|||
</Row>
|
||||
)
|
||||
},
|
||||
decoratorOption (vnode) {
|
||||
if (vnode.data && vnode.data.directives) {
|
||||
const directive = find(vnode.data.directives, ['name', 'decorator']) || {}
|
||||
return directive.value || null
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
},
|
||||
decoratorChildren (vnodes) {
|
||||
const { FormProps } = this
|
||||
const getFieldDecorator = FormProps.form.getFieldDecorator
|
||||
vnodes.forEach((vnode, index) => {
|
||||
const option = this.decoratorOption(vnode)
|
||||
if (option && option.id) {
|
||||
vnodes[index] = getFieldDecorator(option.id, option.options || {})(vnode)
|
||||
} else if (vnode.children) {
|
||||
vnode.children = this.decoratorChildren(cloneVNodes(vnode.children))
|
||||
} else if (vnode.componentOptions && vnode.componentOptions.children) {
|
||||
vnode.componentOptions.children = this.decoratorChildren(cloneVNodes(vnode.componentOptions.children))
|
||||
}
|
||||
})
|
||||
return vnodes
|
||||
},
|
||||
},
|
||||
|
||||
render () {
|
||||
const { $slots, decoratorFormProps, fieldDecoratorId, fieldDecoratorOptions = {}} = this
|
||||
const child = filterEmpty($slots.default || [])
|
||||
const { $slots, decoratorFormProps, fieldDecoratorId, fieldDecoratorOptions = {}, FormProps } = this
|
||||
let child = filterEmpty($slots.default || [])
|
||||
if (decoratorFormProps.form && fieldDecoratorId && child.length) {
|
||||
const getFieldDecorator = decoratorFormProps.form.getFieldDecorator
|
||||
child[0] = getFieldDecorator(fieldDecoratorId, fieldDecoratorOptions)(child[0])
|
||||
|
@ -351,9 +376,14 @@ export default {
|
|||
!(child.length > 1),
|
||||
'`autoFormCreate` just `decorator` then first children. but you can use JSX to support multiple children',
|
||||
)
|
||||
this.slotDefault = child
|
||||
} else if (FormProps.form) {
|
||||
child = cloneVNodes(child)
|
||||
this.slotDefault = this.decoratorChildren(child)
|
||||
} else {
|
||||
this.slotDefault = child
|
||||
}
|
||||
|
||||
this.slotDefault = child
|
||||
const children = this.renderChildren()
|
||||
return this.renderFormItem(children)
|
||||
},
|
||||
|
|
|
@ -580,7 +580,7 @@ exports[`renders ./components/form/demo/validate-other.vue correctly 1`] = `
|
|||
</div>
|
||||
</div>
|
||||
<div class="ant-row ant-form-item">
|
||||
<div class="ant-col-6 ant-form-item-label"><label title="Dragger" class="">Dragger</label></div>
|
||||
<div class="ant-col-6 ant-form-item-label"><label for="dragger" title="Dragger" class="">Dragger</label></div>
|
||||
<div class="ant-col-14 ant-form-item-control-wrapper">
|
||||
<div class="ant-form-item-control"><span class="ant-form-item-children"><div class="dropbox"><span data-__meta="[object Object]" data-__field="[object Object]" id="dragger" class=""><div class="ant-upload ant-upload-drag"><!----></div><div class="ant-upload-list ant-upload-list-text"></div></span></div></span>
|
||||
<!---->
|
||||
|
|
|
@ -10,24 +10,29 @@ Use `setFieldsValue` to set other control's value programmaticly.
|
|||
|
||||
|
||||
<template>
|
||||
<a-form @submit="handleSubmit" :autoFormCreate="(form)=>{this.form = form}">
|
||||
<a-form @submit="handleSubmit" :form="form">
|
||||
<a-form-item
|
||||
label='Note'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="note"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your note!' }]}"
|
||||
>
|
||||
<a-input />
|
||||
<a-input
|
||||
v-decorator="{
|
||||
id: 'note',
|
||||
options: {rules: [{ required: true, message: 'Please input your note!' }]}
|
||||
}"
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
label='Gender'
|
||||
:labelCol="{ span: 5 }"
|
||||
:wrapperCol="{ span: 12 }"
|
||||
fieldDecoratorId="gender"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please select your gender!' }]}"
|
||||
>
|
||||
<a-select
|
||||
v-decorator="{
|
||||
id: 'gender',
|
||||
options: {rules: [{ required: true, message: 'Please select your gender!' }]}
|
||||
}"
|
||||
placeholder='Select a option and change input text above'
|
||||
@change="this.handleSelectChange"
|
||||
>
|
||||
|
@ -50,6 +55,7 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
formLayout: 'horizontal',
|
||||
form: this.$form.createForm(this),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -10,24 +10,32 @@ Perform different check rules according to different situations.
|
|||
|
||||
|
||||
<template>
|
||||
<a-form :autoFormCreate="(form)=>{this.form = form}">
|
||||
<a-form :form="form">
|
||||
<a-form-item
|
||||
:labelCol="formItemLayout.labelCol"
|
||||
:wrapperCol="formItemLayout.wrapperCol"
|
||||
label='Name'
|
||||
fieldDecoratorId="username"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your name' }]}"
|
||||
>
|
||||
<a-input placeholder='Please input your name' />
|
||||
<a-input
|
||||
v-decorator="{
|
||||
id: 'username',
|
||||
options: {rules: [{ required: true, message: 'Please input your name' }]}
|
||||
}"
|
||||
placeholder='Please input your name'
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:labelCol="formItemLayout.labelCol"
|
||||
:wrapperCol="formItemLayout.wrapperCol"
|
||||
label='Nickname'
|
||||
fieldDecoratorId="nickname"
|
||||
:fieldDecoratorOptions="{rules: [{ required: checkNick, message: 'Please input your nickname' }]}"
|
||||
>
|
||||
<a-input placeholder='Please input your nickname' />
|
||||
<a-input
|
||||
v-decorator="{
|
||||
id: 'nickname',
|
||||
options: {rules: [{ required: checkNick, message: 'Please input your nickname' }]}
|
||||
}"
|
||||
placeholder='Please input your nickname'
|
||||
/>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:labelCol="formTailLayout.labelCol"
|
||||
|
@ -64,6 +72,7 @@ export default {
|
|||
checkNick: false,
|
||||
formItemLayout,
|
||||
formTailLayout,
|
||||
form: this.$form.createForm(this),
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -10,25 +10,33 @@ Horizontal login form is often used in navigation bar.
|
|||
|
||||
|
||||
<template>
|
||||
<a-form layout='inline' @submit="handleSubmit" :autoFormCreate="(form)=>{this.form = form}">
|
||||
<template v-if="form">
|
||||
<a-form layout='inline' @submit="handleSubmit" :form="form">
|
||||
<a-form-item
|
||||
:validateStatus="userNameError() ? 'error' : ''"
|
||||
:help="userNameError() || ''"
|
||||
fieldDecoratorId="userName"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your username!' }]}"
|
||||
>
|
||||
<a-input placeholder='Username'>
|
||||
<a-input
|
||||
placeholder='Username'
|
||||
v-decorator="{
|
||||
id: 'userName',
|
||||
options: {rules: [{ required: true, message: 'Please input your username!' }]}
|
||||
}"
|
||||
>
|
||||
<a-icon slot="prefix" type='user' style="color:rgba(0,0,0,.25)"/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
:validateStatus="passwordError() ? 'error' : ''"
|
||||
:help="passwordError() || ''"
|
||||
fieldDecoratorId="password"
|
||||
:fieldDecoratorOptions="{rules: [{ required: true, message: 'Please input your Password!' }]}"
|
||||
>
|
||||
<a-input type='password' placeholder='Password'>
|
||||
<a-input
|
||||
v-decorator="{
|
||||
id: 'password',
|
||||
options: {rules: [{ required: true, message: 'Please input your Password!' }]}
|
||||
}"
|
||||
type='password'
|
||||
placeholder='Password'
|
||||
>
|
||||
<a-icon slot="prefix" type='lock' style="color:rgba(0,0,0,.25)"/>
|
||||
</a-input>
|
||||
</a-form-item>
|
||||
|
@ -41,7 +49,6 @@ Horizontal login form is often used in navigation bar.
|
|||
Log in
|
||||
</a-button>
|
||||
</a-form-item>
|
||||
</template>
|
||||
</a-form>
|
||||
</template>
|
||||
|
||||
|
@ -53,7 +60,7 @@ export default {
|
|||
data () {
|
||||
return {
|
||||
hasErrors,
|
||||
form: null,
|
||||
form: this.$form.createForm(this),
|
||||
}
|
||||
},
|
||||
mounted () {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import Vue from 'vue'
|
||||
import Form from './Form'
|
||||
import ref from 'vue-ref'
|
||||
import FormDecoratorDirective from '../_util/FormDecoratorDirective'
|
||||
|
||||
Vue.use(ref, { name: 'ant-ref' })
|
||||
Vue.use(FormDecoratorDirective)
|
||||
|
||||
export { FormProps, FormCreateOption, ValidationRule } from './Form'
|
||||
export { FormItemProps } from './FormItem'
|
||||
|
@ -11,6 +13,7 @@ export { FormItemProps } from './FormItem'
|
|||
Form.install = function (Vue) {
|
||||
Vue.component(Form.name, Form)
|
||||
Vue.component(Form.Item.name, Form.Item)
|
||||
Vue.prototype.$form = Form
|
||||
}
|
||||
|
||||
export default Form
|
||||
|
|
|
@ -11,25 +11,23 @@
|
|||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
| form | 经 `Form.create()` 包装过的组件会自带 `this.form` 属性,直接传给 Form 即可。无需手动设置 | object | 无 |
|
||||
| form | 经 `Form.create()` 包装过的组件会自带 `this.form` 属性,如果使用template语法,可以使用this.$form.createForm(this, options) | object | 无 |
|
||||
| hideRequiredMark | 隐藏所有表单项的必选标记 | Boolean | false |
|
||||
| layout | 表单布局 | 'horizontal'\|'vertical'\|'inline' | 'horizontal' |
|
||||
| autoFormCreate | 自动执行Form.create,建议在template组件下使用,并且不可以和`Form.create()`同时使用 |Function(form)| 无|
|
||||
| options | 对应Form.create(options)的`options` | Object | {} |
|
||||
|
||||
### 事件
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
| --- | --- | --- |
|
||||
| submit | 数据验证成功后回调事件 | Function(e:Event) |
|
||||
|
||||
### autoFormCreate
|
||||
### createForm
|
||||
|
||||
````html
|
||||
<a-form :autoFormCreate="(form)=>{this.form = form}">
|
||||
<a-form :form="form">
|
||||
...
|
||||
</a-form>
|
||||
````
|
||||
如果使用`template`语法,可以使用`autoFormCreate`开启自动校验和数据收集功能,但每一个`Form.Item`仅仅对其第一个子组件进行`decorator`。更加复杂的功能建议使用`JSX`。
|
||||
如果使用`template`语法,可以使用`this.$form.createForm(this, options)`开启自动校验和数据收集功能。
|
||||
|
||||
相关示例如下:
|
||||
|
||||
|
@ -144,7 +142,7 @@ CustomizedForm = Form.create({})(CustomizedForm);
|
|||
1. `getFieldDecorator` 不能用于装饰纯函数组件。
|
||||
2. `getFieldDecorator` 调用不能位于纯函数组件中 <https://cn.vuejs.org/v2/api/#functional>。
|
||||
|
||||
#### getFieldDecorator(id, options) 参数
|
||||
#### getFieldDecorator(id, options) \| v-decorator="id, options" 参数
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -162,7 +160,7 @@ CustomizedForm = Form.create({})(CustomizedForm);
|
|||
|
||||
注意:
|
||||
|
||||
- 一个 Form.Item 建议只放一个被 getFieldDecorator 装饰过的 child,当有多个被装饰过的 child 时,`help` `required` `validateStatus` 无法自动生成。
|
||||
- 一个 Form.Item 建议只放一个被 getFieldDecorator或v-decorator 装饰过的 child,当有多个被装饰过的 child 时,`help` `required` `validateStatus` 无法自动生成。
|
||||
|
||||
| 参数 | 说明 | 类型 | 默认值 |
|
||||
| --- | --- | --- | --- |
|
||||
|
@ -175,8 +173,6 @@ CustomizedForm = Form.create({})(CustomizedForm);
|
|||
| required | 是否必填,如不设置,则会根据校验规则自动生成 | boolean | false |
|
||||
| validateStatus | 校验状态,如不设置,则会根据校验规则自动生成,可选:'success' 'warning' 'error' 'validating' | string | |
|
||||
| wrapperCol | 需要为输入控件设置布局样式时,使用该属性,用法同 labelCol | [object](/ant-design-vue/components/grid-cn/#Col) | |
|
||||
| fieldDecoratorId | 对应`getFieldDecorator(id, options)`的第一个参数`id`,如需收集数据需要设置该字段 | string | 无 |
|
||||
| fieldDecoratorOptions | 对应`getFieldDecorator(id, options)`的第二个参数`options` | object | {} |
|
||||
|
||||
### 校验规则
|
||||
|
||||
|
|
|
@ -577,9 +577,11 @@ function createBaseForm (option = {}, mixins = []) {
|
|||
on: $listeners,
|
||||
ref: 'WrappedComponent',
|
||||
}
|
||||
return <WrappedComponent {...wrappedComponentProps}>{$slots.default}</WrappedComponent>
|
||||
|
||||
return WrappedComponent ? <WrappedComponent {...wrappedComponentProps}>{$slots.default}</WrappedComponent> : null
|
||||
},
|
||||
}
|
||||
if (!WrappedComponent) return Form
|
||||
if (Array.isArray(WrappedComponent.props)) {
|
||||
const newProps = {}
|
||||
WrappedComponent.props.forEach((prop) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "ant-design-vue",
|
||||
"version": "1.1.9",
|
||||
"version": "1.1.10-beta",
|
||||
"title": "Ant Design Vue",
|
||||
"description": "An enterprise-class UI design language and Vue-based implementation",
|
||||
"keywords": [
|
||||
|
|
Loading…
Reference in New Issue