feat: add vc-form demo

pull/165/head
tangjinzhou 2018-05-04 12:16:17 +08:00
parent 29b9c51f57
commit f1d987b72b
8 changed files with 645 additions and 32 deletions

View File

@ -60,7 +60,7 @@ export function cloneElement (n, nodeProps, deep) {
return null
}
const node = cloneVNode(ele, deep)
const { props = {}, key, on = {}, children } = nodeProps
const { props = {}, key, on = {}, children, directives = [] } = nodeProps
const data = node.data || {}
let cls = {}
let style = {}
@ -101,6 +101,7 @@ export function cloneElement (n, nodeProps, deep) {
class: cls,
domProps: { ...data.domProps, ...domProps },
scopedSlots: { ...data.scopedSlots, ...scopedSlots },
directives: [...(data.directives || []), ...directives],
})
if (node.componentOptions) {

View File

@ -0,0 +1,123 @@
/* eslint react/no-multi-comp:0, no-console:0 */
import { createForm } from '../index'
import { regionStyle, errorStyle } from './styles'
import BaseMixin from '../../_util/BaseMixin'
const Email = {
props: {
form: Object,
},
methods: {
checkSpecial (rule, value, callback) {
setTimeout(() => {
if (value === 'yiminghe@gmail.com') {
callback('can not be!')
} else {
callback()
}
}, 1000)
},
},
render () {
const { getFieldProps, getFieldError, isFieldValidating } = this.form
const errors = getFieldError('email')
return (<div style={ regionStyle }>
<div>email validate onBlur</div>
<div>
<input {...getFieldProps('email', {
initialValue: '',
validateFirst: true,
rules: [
{
required: true,
},
{
type: 'email',
message: '错误的 email 格式',
},
this.checkSpecial,
],
validateTrigger: 'blur',
})}
/></div>
<div style={errorStyle}>
{errors ? errors.join(',') : null}
</div>
<div style={errorStyle}>
{isFieldValidating('email') ? 'validating' : null}
</div>
</div>)
},
}
const Form = {
mixins: [BaseMixin],
props: {
form: Object,
},
data () {
return {
loading: true,
}
},
mounted () {
setTimeout(() => {
this.setState({
loading: false,
}, () => {
setTimeout(() => {
this.form.setFieldsInitialValue({
email: 'xx@gmail.com',
})
}, 1000)
})
}, 1000)
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.submit((callback) => {
setTimeout(() => {
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
callback()
})
}, 1000)
})
},
reset (e) {
e.preventDefault()
this.form.resetFields()
},
},
render () {
if (this.loading) {
return <b>loading</b>
}
const { form } = this
const disabled = form.isFieldsValidating() || form.isSubmitting()
return (<div style={{ margin: 20 }}>
<h2>async init field</h2>
<form onSubmit={this.onSubmit}>
<Email form={ form }/>
<div style={ regionStyle }>
<button disabled={disabled} type='submit'>submit</button>
&nbsp;{disabled ? <span style={{ color: 'red' }}>disabled</span> : null}&nbsp;
<button disabled={disabled} onClick={this.reset}>reset</button>
</div>
</form>
</div>)
},
}
export default createForm()(Form)

View File

@ -0,0 +1,201 @@
/* eslint react/no-multi-comp:0, no-console:0 */
import { createForm } from '../index'
import BaseMixin from '../../_util/BaseMixin'
const Form1 = {
mixins: [BaseMixin],
props: {
form: Object,
},
data () {
return {
useInput: true,
}
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
})
},
changeUseInput (e) {
this.setState({
useInput: e.target.checked,
})
},
},
render () {
const { getFieldError, getFieldDecorator } = this.form
return (
<form onSubmit={this.onSubmit}>
<h2>situation 1</h2>
{this.useInput ? getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name 1?',
}],
})(<input/>) : null}
<span>text content</span>
{this.useInput ? null : getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name 2?',
}],
})(<input />)}
<div>
<label>
<input type='checkbox' checked={this.useInput} onInput={this.changeUseInput} />
change input
</label>
{(getFieldError('name') || []).join(', ')}
</div>
<button>Submit</button>
</form>
)
},
}
const Form2 = {
mixins: [BaseMixin],
props: {
form: Object,
},
data () {
return {
useInput: true,
}
},
beforeMount () {
const { getFieldDecorator } = this.form
this.nameDecorator = getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name?',
}],
})
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
})
},
changeUseInput (e) {
this.setState({
useInput: e.target.checked,
})
},
},
render () {
const { getFieldError } = this.form
return (
<form onSubmit={this.onSubmit}>
<h2>situation 2</h2>
{this.useInput ? this.nameDecorator(<input />) : null}
<span>text content</span>
{this.useInput ? null : this.nameDecorator(<input />)}
<div>
<label>
<input type='checkbox' checked={this.useInput} onInput={this.changeUseInput} />
change input
</label>
{(getFieldError('name') || []).join(', ')}
</div>
<button>Submit</button>
</form>
)
},
}
const Form3 = {
mixins: [BaseMixin],
props: {
form: Object,
},
data () {
return {
useInput: false,
}
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
})
},
changeUseInput (e) {
this.setState({
useInput: e.target.checked,
})
},
},
render () {
const { getFieldError, getFieldDecorator } = this.form
return (
<form onSubmit={this.onSubmit}>
<h2>situation 3</h2>
{getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name 1?',
}],
})(<input />)}
{this.useInput ? null : getFieldDecorator('name2', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name 2?',
}],
})(<input />)}
<div>
<label>
<input type='checkbox' checked={this.useInput} onInput={this.changeUseInput} />
Hide second input
</label>
{(getFieldError('name') || []).join(', ')}
</div>
<button>Submit</button>
</form>
)
},
}
const WrappedForm1 = createForm()(Form1)
const WrappedForm2 = createForm()(Form2)
const WrappedForm3 = createForm()(Form3)
export default {
render () {
return (
<div>
<WrappedForm1 />
<WrappedForm2 />
<WrappedForm3 />
</div>
)
},
}

View File

@ -0,0 +1,131 @@
/* eslint react/no-multi-comp:0, no-console:0 */
import { createForm } from '../index'
import { regionStyle, errorStyle } from './styles'
const Email = {
props: {
form: Object,
hidden: Boolean,
},
render () {
const { hidden, form } = this
const { getFieldProps, getFieldError, isFieldValidating } = form
const errors = getFieldError('email')
const style = {
...regionStyle,
display: hidden ? 'none' : '',
}
return (<div style={ style }>
<div>email:
<input {...getFieldProps('email', {
rules: [
{
required: true,
},
{
type: 'email',
message: '错误的 email 格式',
},
],
hidden,
})}
/></div>
{errors ? <div style={errorStyle}>{errors.join(',')}</div> : null}
{isFieldValidating('email') ? <div style={errorStyle}>validating</div> : null}
</div>)
},
}
const User = {
props: {
form: Object,
},
render () {
const { getFieldProps, getFieldError, isFieldValidating } = this.form
const errors = getFieldError('user')
return (<div style={ regionStyle }>
<div>user:
<input {...getFieldProps('user', {
initialValue: 'x',
rules: [
{
required: true,
},
],
})}
/>
</div>
{errors ? <div style={errorStyle}>{errors.join(',')}</div> : null}
{isFieldValidating('user') ? <div style={errorStyle}>validating</div> : null}
</div>)
},
}
const Form = {
props: {
form: Object,
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
})
},
},
render () {
const { form } = this
const { getFieldProps, getFieldValue } = form
return (<div style={{ margin: 20 }}>
<h2>overview</h2>
<form onSubmit={this.onSubmit}>
<div style={ regionStyle }>
<div>
<label>remove/add user:
<input
type='checkbox'
{...getFieldProps('remove_user', {
// initialValue:true,
valuePropName: 'checked',
})}
/>
</label>
</div>
</div>
{ getFieldValue('remove_user') ? null : <User form={ form }/>}
<div style={ regionStyle }>
<div>
<label>hide/show email:
<input
type='checkbox'
{...getFieldProps('hide_email', {
// initialValue:true,
valuePropName: 'checked',
})}
/></label>
</div>
</div>
<Email form={ form } hidden={!!getFieldValue('hide_email')}/>
<div style={ regionStyle }>
<button>submit</button>
</div>
</form>
</div>)
},
}
export default createForm()(Form)

View File

@ -0,0 +1,83 @@
/* eslint react/no-multi-comp:0, no-console:0 */
import { createForm } from '../index'
import { regionStyle, errorStyle } from './styles'
function getFileValueProps (value) {
if (value && value.target) {
return {
value: value.target.value,
}
}
return {
value,
}
}
function getValueFromFileEvent ({ target }) {
return {
target,
}
}
const Form = {
props: {
form: Object,
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
console.log(error, values)
if (!error) {
console.log('校验通过')
}
})
},
checkSize (rule, value, callback) {
if (value && value.target) {
const files = value.target.files
if (files[0]) {
callback(files[0].size > 1000000 ? 'file size must be less than 1M' : undefined)
} else {
callback()
}
} else {
callback()
}
},
},
render () {
const { getFieldProps, getFieldError } = this.form
const errors = getFieldError('attachment')
return (<div
style={ regionStyle }
>
<div>attachment:</div>
<div>
<input type='file' {...getFieldProps('attachment', {
getValueProps: getFileValueProps,
getValueFromEvent: getValueFromFileEvent,
rules: [this.checkSize],
})}
/>
</div>
<div style={errorStyle}>
{(errors) ? errors.join(',') : null}
</div>
<button onClick={this.onSubmit}>submit</button>
</div>)
},
}
const NewForm = createForm()(Form)
export default {
render () {
return (<div>
<h2>input[type="file"]</h2>
<NewForm />
</div>)
},
}

View File

@ -0,0 +1,55 @@
/* eslint react/no-multi-comp:0, no-console:0 */
import { createForm } from '../index'
const Form = {
props: {
form: Object,
},
beforeMount () {
this.nameDecorator = this.form.getFieldDecorator('name', {
initialValue: '',
rules: [{
required: true,
message: 'What\'s your name?',
}],
})
},
methods: {
onSubmit (e) {
e.preventDefault()
this.form.validateFields((error, values) => {
if (!error) {
console.log('ok', values)
} else {
console.log('error', error, values)
}
})
},
onChange (e) {
console.log(e.target.value)
},
},
render () {
const { getFieldError } = this.form
return (
<form onSubmit={this.onSubmit}>
{this.nameDecorator(
<input
onInput={this.onChange}
/>
)}
<div style={{ color: 'red' }}>
{(getFieldError('name') || []).join(', ')}
</div>
<button>Submit</button>
</form>
)
},
}
export default createForm()(Form)

View File

@ -5,7 +5,9 @@ import set from 'lodash/set'
import createFieldsStore from './createFieldsStore'
import { cloneElement } from '../../_util/vnode'
import BaseMixin from '../../_util/BaseMixin'
import PropTypes from '../../_util/vue-types'
import { getOptionProps, getEvents } from '../../_util/props-util'
// import PropTypes from '../../_util/vue-types'
import {
argumentContainer,
identity,
@ -18,7 +20,7 @@ import {
flattenArray,
} from './utils'
const DEFAULT_TRIGGER = 'change'
const DEFAULT_TRIGGER = 'input'
function createBaseForm (option = {}, mixins = []) {
const {
@ -38,10 +40,10 @@ function createBaseForm (option = {}, mixins = []) {
return function decorate (WrappedComponent) {
const Form = {
mixins: [BaseMixin, ...mixins],
props: {
hideRequiredMark: PropTypes.bool,
layout: PropTypes.string,
},
// props: {
// hideRequiredMark: PropTypes.bool,
// layout: PropTypes.string,
// },
data () {
const fields = mapPropsToFields && mapPropsToFields(this.$props)
this.fieldsStore = createFieldsStore(fields || {})
@ -148,10 +150,11 @@ function createBaseForm (option = {}, mixins = []) {
},
getFieldDecorator (name, fieldOption) {
const { directives, props } = this.getFieldProps(name, fieldOption)
const { props, ...restProps } = this.getFieldProps(name, fieldOption)
return (fieldElem) => {
const fieldMeta = this.fieldsStore.getFieldMeta(name)
const originalProps = fieldElem.props
const originalProps = getOptionProps(fieldElem)
const originalEvents = getEvents(fieldElem)
if (process.env.NODE_ENV !== 'production') {
const valuePropName = fieldMeta.valuePropName
warning(
@ -170,14 +173,26 @@ function createBaseForm (option = {}, mixins = []) {
)
}
fieldMeta.originalProps = originalProps
fieldMeta.ref = fieldElem.ref
return cloneElement(fieldElem, {
// fieldMeta.ref = fieldElem.data && fieldElem.data.ref
const newProps = {
props: {
...props,
...this.fieldsStore.getFieldValuePropValue(fieldMeta),
},
directives,
...restProps,
}
newProps.domProps.value = newProps.props.value
const newEvents = {}
Object.keys(newProps.on).forEach((key) => {
if (originalEvents[key]) {
const triggerEvents = newProps.on[key]
newEvents[key] = (...args) => {
originalEvents[key](...args)
triggerEvents(...args)
}
}
})
return cloneElement(fieldElem, { ...newProps, on: newEvents })
}
},
@ -221,9 +236,8 @@ function createBaseForm (option = {}, mixins = []) {
const inputProps = {
...this.fieldsStore.getFieldValuePropValue(fieldOption),
// ref: name,
on: {},
}
const saveRef = this.getCacheBind(name, `${name}__ref`, this.saveRef)
const inputListeners = {}
if (fieldNameProp) {
inputProps[fieldNameProp] = name
}
@ -231,13 +245,13 @@ function createBaseForm (option = {}, mixins = []) {
const validateRules = normalizeValidateRules(validate, rules, validateTrigger)
const validateTriggers = getValidateTriggers(validateRules)
validateTriggers.forEach((action) => {
if (inputProps[action]) return
inputProps[action] = this.getCacheBind(name, action, this.onCollectValidate)
if (inputListeners[action]) return
inputListeners[action] = this.getCacheBind(name, action, this.onCollectValidate)
})
// make sure that the value will be collect
if (trigger && validateTriggers.indexOf(trigger) === -1) {
inputProps.on[trigger] = this.getCacheBind(name, trigger, this.onCollect)
inputListeners[trigger] = this.getCacheBind(name, trigger, this.onCollect)
}
const meta = {
@ -256,11 +270,16 @@ function createBaseForm (option = {}, mixins = []) {
return {
props: inputProps,
domProps: {
value: inputProps.value,
},
directives: [
{ name: 'ant-form-item-ref-cal', value: (component) => {
saveRef(component)
} },
{
name: 'ant-ref',
value: this.getCacheBind(name, `${name}__ref`, this.saveRef),
},
],
on: inputListeners,
}
},
@ -342,16 +361,16 @@ function createBaseForm (option = {}, mixins = []) {
return
}
this.recoverClearedField(name)
const fieldMeta = this.fieldsStore.getFieldMeta(name)
if (fieldMeta) {
const ref = fieldMeta.ref
if (ref) {
if (typeof ref === 'string') {
throw new Error(`can not set ref string for ${name}`)
}
ref(component)
}
}
// const fieldMeta = this.fieldsStore.getFieldMeta(name)
// if (fieldMeta) {
// const ref = fieldMeta.ref
// if (ref) {
// if (typeof ref === 'string') {
// throw new Error(`can not set ref string for ${name}`)
// }
// ref(component)
// }
// }
this.instances[name] = component
},

View File

@ -4,8 +4,8 @@ import createFormField from './createFormField'
import formShape from './propTypes'
import Vue from 'vue'
Vue.directive('ant-form-item-ref-cal', {
inserted: function (el, binding, vnode) {
Vue.directive('ant-ref', {
bind: function (el, binding, vnode) {
binding.value(vnode)
},
unbind: function (el, binding, vnode) {