From 4f0c5b8ce123e2d04a79e85a71fd6c8645aee138 Mon Sep 17 00:00:00 2001 From: tangjinzhou <415800467@qq.com> Date: Fri, 4 May 2018 12:16:17 +0800 Subject: [PATCH] feat: add vc-form demo --- components/_util/vnode.js | 3 +- components/vc-form/demo/async-init.js | 123 ++++++++++++ components/vc-form/demo/dynamic-fields.js | 201 +++++++++++++++++++ components/vc-form/demo/dynamic.js | 131 ++++++++++++ components/vc-form/demo/file-input.js | 83 ++++++++ components/vc-form/demo/getFieldDecorator.js | 55 +++++ components/vc-form/src/createBaseForm.jsx | 77 ++++--- components/vc-form/src/index.jsx | 4 +- 8 files changed, 645 insertions(+), 32 deletions(-) create mode 100644 components/vc-form/demo/async-init.js create mode 100644 components/vc-form/demo/dynamic-fields.js create mode 100644 components/vc-form/demo/dynamic.js create mode 100644 components/vc-form/demo/file-input.js create mode 100644 components/vc-form/demo/getFieldDecorator.js diff --git a/components/_util/vnode.js b/components/_util/vnode.js index 4f7e91e0c..a7e40ec98 100644 --- a/components/_util/vnode.js +++ b/components/_util/vnode.js @@ -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) { diff --git a/components/vc-form/demo/async-init.js b/components/vc-form/demo/async-init.js new file mode 100644 index 000000000..e46039e1f --- /dev/null +++ b/components/vc-form/demo/async-init.js @@ -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 (
+
email validate onBlur
+
+
+
+ {errors ? errors.join(',') : null} +
+
+ {isFieldValidating('email') ? 'validating' : null} +
+
) + }, +} + +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 loading + } + const { form } = this + const disabled = form.isFieldsValidating() || form.isSubmitting() + return (
+

async init field

+
+ + +
+ +  {disabled ? disabled : null}  + +
+ +
) + }, +} + +export default createForm()(Form) diff --git a/components/vc-form/demo/dynamic-fields.js b/components/vc-form/demo/dynamic-fields.js new file mode 100644 index 000000000..5bf0fa7e7 --- /dev/null +++ b/components/vc-form/demo/dynamic-fields.js @@ -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 ( +
+

situation 1

+ {this.useInput ? getFieldDecorator('name', { + initialValue: '', + rules: [{ + required: true, + message: 'What\'s your name 1?', + }], + })() : null} + text content + {this.useInput ? null : getFieldDecorator('name', { + initialValue: '', + rules: [{ + required: true, + message: 'What\'s your name 2?', + }], + })()} +
+ + {(getFieldError('name') || []).join(', ')} +
+ +
+ ) + }, +} + +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 ( +
+

situation 2

+ {this.useInput ? this.nameDecorator() : null} + text content + {this.useInput ? null : this.nameDecorator()} +
+ + {(getFieldError('name') || []).join(', ')} +
+ +
+ ) + }, +} + +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 ( +
+

situation 3

+ {getFieldDecorator('name', { + initialValue: '', + rules: [{ + required: true, + message: 'What\'s your name 1?', + }], + })()} + {this.useInput ? null : getFieldDecorator('name2', { + initialValue: '', + rules: [{ + required: true, + message: 'What\'s your name 2?', + }], + })()} +
+ + {(getFieldError('name') || []).join(', ')} +
+ +
+ ) + }, +} + +const WrappedForm1 = createForm()(Form1) +const WrappedForm2 = createForm()(Form2) +const WrappedForm3 = createForm()(Form3) + +export default { + render () { + return ( +
+ + + +
+ ) + }, +} diff --git a/components/vc-form/demo/dynamic.js b/components/vc-form/demo/dynamic.js new file mode 100644 index 000000000..dd56eaaa7 --- /dev/null +++ b/components/vc-form/demo/dynamic.js @@ -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 (
+
email: +
+ + {errors ?
{errors.join(',')}
: null} + + {isFieldValidating('email') ?
validating
: null} +
) + }, + +} + +const User = { + props: { + form: Object, + }, + render () { + const { getFieldProps, getFieldError, isFieldValidating } = this.form + const errors = getFieldError('user') + return (
+
user: + +
+ {errors ?
{errors.join(',')}
: null} + + {isFieldValidating('user') ?
validating
: null} +
) + }, +} + +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 (
+

overview

+
+
+
+ +
+
+ + { getFieldValue('remove_user') ? null : } + +
+
+ +
+
+ +
) + }, +} + +export default createForm()(Form) diff --git a/components/vc-form/demo/file-input.js b/components/vc-form/demo/file-input.js new file mode 100644 index 000000000..0a723a52e --- /dev/null +++ b/components/vc-form/demo/file-input.js @@ -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 (
+
attachment:
+
+ +
+
+ {(errors) ? errors.join(',') : null} +
+ +
) + }, +} + +const NewForm = createForm()(Form) + +export default { + render () { + return (
+

input[type="file"]

+ +
) + }, +} diff --git a/components/vc-form/demo/getFieldDecorator.js b/components/vc-form/demo/getFieldDecorator.js new file mode 100644 index 000000000..76285870f --- /dev/null +++ b/components/vc-form/demo/getFieldDecorator.js @@ -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 ( +
+ {this.nameDecorator( + + )} +
+ {(getFieldError('name') || []).join(', ')} +
+ +
+ ) + }, +} + +export default createForm()(Form) diff --git a/components/vc-form/src/createBaseForm.jsx b/components/vc-form/src/createBaseForm.jsx index 4384cb712..07a85baf7 100644 --- a/components/vc-form/src/createBaseForm.jsx +++ b/components/vc-form/src/createBaseForm.jsx @@ -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 }, diff --git a/components/vc-form/src/index.jsx b/components/vc-form/src/index.jsx index d54a498b7..4d3bdf6d8 100644 --- a/components/vc-form/src/index.jsx +++ b/components/vc-form/src/index.jsx @@ -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) {