From 9326ad84f8ba792749f90eb401e1d6bc453c4fc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=98=89=E6=B6=B5?= Date: Fri, 7 Feb 2020 15:18:46 +0800 Subject: [PATCH] feat: add form component --- src/field/index.js | 56 ++++++++++++++++-- src/form/README.md | 30 ++++++++++ src/form/README.zh-CN.md | 31 ++++++++++ src/form/demo/index.vue | 58 +++++++++++++++++++ src/form/index.js | 36 ++++++++++++ src/form/test/__snapshots__/demo.spec.js.snap | 35 +++++++++++ src/form/test/demo.spec.js | 4 ++ src/form/test/index.spec.js | 1 + 8 files changed, 245 insertions(+), 6 deletions(-) create mode 100644 src/form/README.md create mode 100644 src/form/README.zh-CN.md create mode 100644 src/form/demo/index.vue create mode 100644 src/form/index.js create mode 100644 src/form/test/__snapshots__/demo.spec.js.snap create mode 100644 src/form/test/demo.spec.js create mode 100644 src/form/test/index.spec.js diff --git a/src/field/index.js b/src/field/index.js index 2bb812c91..299f6418e 100644 --- a/src/field/index.js +++ b/src/field/index.js @@ -15,9 +15,16 @@ const [createComponent, bem] = createNamespace('field'); export default createComponent({ inheritAttrs: false, + inject: { + vanForm: { + default: null, + }, + }, + props: { ...cellProps, name: String, + rules: Array, error: Boolean, disabled: Boolean, readonly: Boolean, @@ -44,6 +51,8 @@ export default createComponent({ data() { return { focused: false, + validateError: false, + validateMessage: '', }; }, @@ -56,6 +65,16 @@ export default createComponent({ mounted() { this.format(); this.$nextTick(this.adjustSize); + + if (this.vanForm) { + this.vanForm.fields.push(this); + } + }, + + beforeDestroy() { + if (this.vanForm) { + this.vanForm.fields = this.vanForm.fields.fiilter(item => item !== this); + } }, computed: { @@ -106,6 +125,23 @@ export default createComponent({ } }, + // @exposed-api + validate() { + if (!this.rules) { + return true; + } + + return !this.rules.some(rule => { + if (rule.required && !this.value) { + this.validateError = true; + this.validateMessage = rule.message; + return true; + } + + return false; + }); + }, + format(target = this.$refs.input) { if (!target) { return; @@ -316,6 +352,18 @@ export default createComponent({ ); } }, + + genMessage() { + const message = this.errorMessage || this.validateMessage; + + if (message) { + return ( +
+ {message} +
+ ); + } + }, }, render() { @@ -343,7 +391,7 @@ export default createComponent({ titleClass={[bem('label', labelAlign), this.labelClass]} arrowDirection={this.arrowDirection} class={bem({ - error: this.error, + error: this.error || this.validateError, [`label-${labelAlign}`]: labelAlign, 'min-height': this.type === 'textarea' && !this.autosize, })} @@ -365,11 +413,7 @@ export default createComponent({ )} {this.genWordLimit()} - {this.errorMessage && ( -
- {this.errorMessage} -
- )} + {this.genMessage()} ); }, diff --git a/src/form/README.md b/src/form/README.md new file mode 100644 index 000000000..e0452706e --- /dev/null +++ b/src/form/README.md @@ -0,0 +1,30 @@ +# Form + +### Install + +```js +import Vue from 'vue'; +import { Form } from 'vant'; + +Vue.use(Form); +``` + +## Usage + +### Basic Usage + +## API + +### Props + +| Attribute | Description | Type | Default | +|------|------|------|------| + +### Events + +| Event | Description | Arguments | + +### Slots + +| Name | Description | +|------|------| diff --git a/src/form/README.zh-CN.md b/src/form/README.zh-CN.md new file mode 100644 index 000000000..f2458d0d2 --- /dev/null +++ b/src/form/README.zh-CN.md @@ -0,0 +1,31 @@ +# Form 表单 + +### 引入 + +```js +import Vue from 'vue'; +import { Form } from 'vant'; + +Vue.use(Form); +``` + +## 代码演示 + +### 基础用法 + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +|------|------|------|------| + +### Events + +| 事件名 | 说明 | 回调参数 | +|------|------|------| + +### Slots + +| 名称 | 说明 | +|------|------| diff --git a/src/form/demo/index.vue b/src/form/demo/index.vue new file mode 100644 index 000000000..2834d9cb9 --- /dev/null +++ b/src/form/demo/index.vue @@ -0,0 +1,58 @@ + + + + + diff --git a/src/form/index.js b/src/form/index.js new file mode 100644 index 000000000..f760be921 --- /dev/null +++ b/src/form/index.js @@ -0,0 +1,36 @@ +// Utils +import { createNamespace } from '../utils'; + +const [createComponent, bem] = createNamespace('form'); + +export default createComponent({ + provide() { + return { + vanForm: this, + }; + }, + + data() { + return { + fields: [], + }; + }, + + methods: { + onSubmit(event) { + event.preventDefault(); + + const results = this.fields.map(item => item.validate()); + + console.log(results); + }, + }, + + render() { + return ( +
+ {this.slots()} +
+ ); + }, +}); diff --git a/src/form/test/__snapshots__/demo.spec.js.snap b/src/form/test/__snapshots__/demo.spec.js.snap new file mode 100644 index 000000000..a479872af --- /dev/null +++ b/src/form/test/__snapshots__/demo.spec.js.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders demo correctly 1`] = ` +
+
+
+
+
username
+
+
+
+
+
+
password
+
+
+
+
+
+
agree
+
+
+
+ +
+
+
+
+
+
+
+`; diff --git a/src/form/test/demo.spec.js b/src/form/test/demo.spec.js new file mode 100644 index 000000000..5c70922b5 --- /dev/null +++ b/src/form/test/demo.spec.js @@ -0,0 +1,4 @@ +import Demo from '../demo'; +import { snapshotDemo } from '../../../test/demo'; + +snapshotDemo(Demo); diff --git a/src/form/test/index.spec.js b/src/form/test/index.spec.js new file mode 100644 index 000000000..e76fc2be8 --- /dev/null +++ b/src/form/test/index.spec.js @@ -0,0 +1 @@ +// import { mount } from '../../../test';