mirror of
https://gitee.com/vant-contrib/vant.git
synced 2025-04-06 03:57:59 +08:00
feat(Form): support pattern rule (#5700)
This commit is contained in:
parent
5d0a1304bc
commit
529e117096
@ -159,6 +159,16 @@ export default createComponent({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
|
runRuleSync(rule) {
|
||||||
|
if (rule.required && this.formValueEmpty) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rule.pattern && !rule.pattern.test(this.formValue)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
},
|
||||||
|
|
||||||
runRules(rules) {
|
runRules(rules) {
|
||||||
return rules.reduce(
|
return rules.reduce(
|
||||||
(promise, rule) =>
|
(promise, rule) =>
|
||||||
@ -167,7 +177,7 @@ export default createComponent({
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rule.required && this.formValueEmpty) {
|
if (!this.runRuleSync(rule)) {
|
||||||
this.validateMessage = rule.message;
|
this.validateMessage = rule.message;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -57,9 +57,25 @@ export default {
|
|||||||
### Validate Rules
|
### Validate Rules
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-form validate-first @submit="onSubmit" @failed="onFailed">
|
<van-form validate-first @failed="onFailed">
|
||||||
<van-field v-model="phone" name="phone" label="Phone" :rules="phoneRules" />
|
<van-field
|
||||||
<van-field v-model="code" name="code" label="Code" :rules="codeRules" />
|
v-model="value1"
|
||||||
|
name="pattern"
|
||||||
|
placeholder="USe pattern"
|
||||||
|
:rules="[{ pattern, message: 'Error message }]"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="value2"
|
||||||
|
name="validator"
|
||||||
|
placeholder="Use validator"
|
||||||
|
:rules="[{ validator, message: 'Error message }]"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="value3"
|
||||||
|
name="asyncValidator"
|
||||||
|
placeholder="Use async validator"
|
||||||
|
:rules="[{ validator: asyncValidator, message: 'Error message }]"
|
||||||
|
/>
|
||||||
<div style="margin: 16px;">
|
<div style="margin: 16px;">
|
||||||
<van-button round block type="info" native-type="submit">
|
<van-button round block type="info" native-type="submit">
|
||||||
Submit
|
Submit
|
||||||
@ -73,24 +89,18 @@ import { Toast } from 'vant';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
this.phoneRules = [
|
|
||||||
{ required: true, message: 'Phone is required' },
|
|
||||||
{ validator: this.phoneValidator, message: 'Incorrect phone' },
|
|
||||||
];
|
|
||||||
this.codeRules = [
|
|
||||||
{ required: true, message: 'Code is required' },
|
|
||||||
{ validator: this.codeValidator, message: 'Incorrect code' },
|
|
||||||
];
|
|
||||||
return {
|
return {
|
||||||
code: '',
|
value1: '',
|
||||||
phone: '',
|
value2: '',
|
||||||
|
value3: '',
|
||||||
|
pattern: /\d{6}/,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
phoneValidator(val) {
|
validator(val) {
|
||||||
return /1\d{10}/.test(val);
|
return /1\d{10}/.test(val);
|
||||||
},
|
},
|
||||||
codeValidator(val) {
|
asyncValidator(val) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
Toast.loading('Validating...');
|
Toast.loading('Validating...');
|
||||||
|
|
||||||
@ -100,9 +110,6 @@ export default {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSubmit(values) {
|
|
||||||
console.log('submit', values);
|
|
||||||
},
|
|
||||||
onFailed(errorInfo) {
|
onFailed(errorInfo) {
|
||||||
console.log('failed', errorInfo);
|
console.log('failed', errorInfo);
|
||||||
},
|
},
|
||||||
@ -433,6 +440,7 @@ export default {
|
|||||||
| message | Error message | *string* |
|
| message | Error message | *string* |
|
||||||
| required | Whether to be a required field | *boolean* |
|
| required | Whether to be a required field | *boolean* |
|
||||||
| validator | Custom validator | *() => boolean \| Promise* |
|
| validator | Custom validator | *() => boolean \| Promise* |
|
||||||
|
| pattern `v2.5.3` | Regex pattern | *RegExp* |
|
||||||
| trigger `v2.5.2` | When to validate the form,can be set to `onChange`、`onBlur` | *string* |
|
| trigger `v2.5.2` | When to validate the form,can be set to `onChange`、`onBlur` | *string* |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
@ -17,7 +17,7 @@ Vue.use(Form);
|
|||||||
|
|
||||||
### 基础用法
|
### 基础用法
|
||||||
|
|
||||||
在表单中,每个 [Field 组件](#/zh-CN/field) 代表一个表单项,使用 Field 的`rules`属性可以定义校验规则
|
在表单中,每个 [Field 组件](#/zh-CN/field) 代表一个表单项,使用 Field 的`rules`属性定义校验规则
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-form @submit="onSubmit">
|
<van-form @submit="onSubmit">
|
||||||
@ -62,12 +62,31 @@ export default {
|
|||||||
|
|
||||||
### 校验规则
|
### 校验规则
|
||||||
|
|
||||||
通过`rules`中的`validator`字段定义校验函数
|
通过`rules`定义表单校验规则,可用字段见[下方表格](#/zh-CN/form#rule-shu-ju-jie-gou)
|
||||||
|
|
||||||
```html
|
```html
|
||||||
<van-form validate-first @submit="onSubmit" @failed="onFailed">
|
<van-form validate-first @failed="onFailed">
|
||||||
<van-field v-model="phone" name="phone" label="手机号" :rules="phoneRules" />
|
<!-- 通过 pattern 进行正则校验 -->
|
||||||
<van-field v-model="code" name="code" label="验证码" :rules="codeRules" />
|
<van-field
|
||||||
|
v-model="value1"
|
||||||
|
name="pattern"
|
||||||
|
placeholder="正则校验"
|
||||||
|
:rules="[{ pattern, message: '请输入正确内容 }]"
|
||||||
|
/>
|
||||||
|
<!-- 通过 validator 进行函数校验 -->
|
||||||
|
<van-field
|
||||||
|
v-model="value2"
|
||||||
|
name="validator"
|
||||||
|
placeholder="函数校验"
|
||||||
|
:rules="[{ validator, message: '请输入正确内容 }]"
|
||||||
|
/>
|
||||||
|
<!-- 通过 validator 进行异步函数校验 -->
|
||||||
|
<van-field
|
||||||
|
v-model="value3"
|
||||||
|
name="asyncValidator"
|
||||||
|
placeholder="异步函数校验"
|
||||||
|
:rules="[{ validator: asyncValidator, message: '请输入正确内容 }]"
|
||||||
|
/>
|
||||||
<div style="margin: 16px;">
|
<div style="margin: 16px;">
|
||||||
<van-button round block type="info" native-type="submit">
|
<van-button round block type="info" native-type="submit">
|
||||||
提交
|
提交
|
||||||
@ -81,26 +100,20 @@ import { Toast } from 'vant';
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
data() {
|
data() {
|
||||||
this.phoneRules = [
|
|
||||||
{ required: true, message: '请输入手机号' },
|
|
||||||
{ validator: this.phoneValidator, message: '手机号格式错误' },
|
|
||||||
];
|
|
||||||
this.codeRules = [
|
|
||||||
{ required: true, message: '请输入验证码' },
|
|
||||||
{ validator: this.codeValidator, message: '验证码错误' },
|
|
||||||
];
|
|
||||||
return {
|
return {
|
||||||
code: '',
|
value1: '',
|
||||||
phone: '',
|
value2: '',
|
||||||
|
value3: '',
|
||||||
|
pattern: /\d{6}/,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
// 校验函数返回 true 表示校验通过,false 表示不通过
|
// 校验函数返回 true 表示校验通过,false 表示不通过
|
||||||
phoneValidator(val) {
|
validator(val) {
|
||||||
return /1\d{10}/.test(val);
|
return /1\d{10}/.test(val);
|
||||||
},
|
},
|
||||||
// 校验函数返回 Promise 来实现异步校验
|
// 异步校验函数返回 Promise
|
||||||
codeValidator(val) {
|
asyncValidator(val) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
Toast.loading('验证中...');
|
Toast.loading('验证中...');
|
||||||
|
|
||||||
@ -110,9 +123,6 @@ export default {
|
|||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
onSubmit(values) {
|
|
||||||
console.log('submit', values);
|
|
||||||
},
|
|
||||||
onFailed(errorInfo) {
|
onFailed(errorInfo) {
|
||||||
console.log('failed', errorInfo);
|
console.log('failed', errorInfo);
|
||||||
},
|
},
|
||||||
@ -468,8 +478,9 @@ export default {
|
|||||||
|------|------|------|
|
|------|------|------|
|
||||||
| message | 错误提示文案 | *string* |
|
| message | 错误提示文案 | *string* |
|
||||||
| required | 是否为必选字段 | *boolean* |
|
| required | 是否为必选字段 | *boolean* |
|
||||||
| validator | 自定义校验函数 | *() => boolean \| Promise* |
|
| validator | 通过函数进行校验 | *() => boolean \| Promise* |
|
||||||
| trigger `v2.5.2` | 本项规则的校验触发时机,可选值为`onChange`、`onBlur` | *string* |
|
| pattern `v2.5.3` | 通过正则表达式进行校验 | *RegExp* |
|
||||||
|
| trigger `v2.5.2` | 本项规则的触发时机,可选值为`onChange`、`onBlur` | *string* |
|
||||||
|
|
||||||
### Events
|
### Events
|
||||||
|
|
||||||
|
@ -2,18 +2,25 @@
|
|||||||
<demo-block :title="$t('title')">
|
<demo-block :title="$t('title')">
|
||||||
<van-form validate-first @sumbit="onSubmit" @failed="onFailed">
|
<van-form validate-first @sumbit="onSubmit" @failed="onFailed">
|
||||||
<van-field
|
<van-field
|
||||||
v-model="phone"
|
v-model="value1"
|
||||||
name="phone"
|
name="pattern"
|
||||||
:label="$t('phone')"
|
:label="$t('label')"
|
||||||
:rules="phoneRules"
|
:rules="[{ pattern, message: $t('message') }]"
|
||||||
:placeholder="$t('phone')"
|
:placeholder="$t('pattern')"
|
||||||
/>
|
/>
|
||||||
<van-field
|
<van-field
|
||||||
v-model="code"
|
v-model="value2"
|
||||||
name="code"
|
name="validator"
|
||||||
:label="$t('code')"
|
:label="$t('label')"
|
||||||
:rules="codeRules"
|
:rules="[{ validator, message: $t('message') }]"
|
||||||
:placeholder="$t('code')"
|
:placeholder="$t('validator')"
|
||||||
|
/>
|
||||||
|
<van-field
|
||||||
|
v-model="value3"
|
||||||
|
name="asyncValidator"
|
||||||
|
:label="$t('label')"
|
||||||
|
:rules="[{ validator: asyncValidator, message: $t('message') }]"
|
||||||
|
:placeholder="$t('asyncValidator')"
|
||||||
/>
|
/>
|
||||||
<div style="margin: 16px 16px 0;">
|
<div style="margin: 16px 16px 0;">
|
||||||
<van-button round block type="info" native-type="submit">
|
<van-button round block type="info" native-type="submit">
|
||||||
@ -28,66 +35,48 @@
|
|||||||
export default {
|
export default {
|
||||||
i18n: {
|
i18n: {
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
code: '验证码',
|
label: '文本',
|
||||||
phone: '手机号',
|
|
||||||
title: '校验规则',
|
title: '校验规则',
|
||||||
submit: '提交',
|
submit: '提交',
|
||||||
|
message: '请输入正确内容',
|
||||||
|
pattern: '正则校验',
|
||||||
|
validator: '函数校验',
|
||||||
validating: '验证中...',
|
validating: '验证中...',
|
||||||
requireCode: '请输入验证码',
|
asyncValidator: '异步函数校验',
|
||||||
requirePhone: '请输入手机号',
|
|
||||||
incorrectCode: '验证码错误',
|
|
||||||
incorrectPhone: '手机号格式错误',
|
|
||||||
},
|
},
|
||||||
'en-US': {
|
'en-US': {
|
||||||
code: 'Code',
|
label: 'Label',
|
||||||
phone: 'Phone',
|
|
||||||
title: 'Validate Rules',
|
title: 'Validate Rules',
|
||||||
submit: 'Submit',
|
submit: 'Submit',
|
||||||
|
message: 'Error message',
|
||||||
|
pattern: 'Use pattern',
|
||||||
|
validator: 'Use validator',
|
||||||
validating: 'Validating...',
|
validating: 'Validating...',
|
||||||
requireCode: 'Code is required',
|
asyncValidator: 'Use async validator',
|
||||||
requirePhone: 'Phone is required',
|
|
||||||
incorrectCode: 'Incorrect code',
|
|
||||||
incorrectPhone: 'Incorrect phone',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
code: '',
|
value1: '',
|
||||||
phone: '',
|
value2: '',
|
||||||
|
value3: '',
|
||||||
|
pattern: /\d{6}/,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
created() {
|
|
||||||
this.phoneRules = [
|
|
||||||
{ required: true, message: this.$t('requirePhone') },
|
|
||||||
{
|
|
||||||
validator: this.phoneValidator,
|
|
||||||
message: this.$t('incorrectPhone'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
|
|
||||||
this.codeRules = [
|
|
||||||
{ required: true, message: this.$t('requireCode') },
|
|
||||||
{
|
|
||||||
validator: this.codeValidator,
|
|
||||||
message: this.$t('incorrectCode'),
|
|
||||||
},
|
|
||||||
];
|
|
||||||
},
|
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
phoneValidator(val) {
|
validator(val) {
|
||||||
return /1\d{10}/.test(val);
|
return val === '1234';
|
||||||
},
|
},
|
||||||
|
|
||||||
codeValidator(val) {
|
asyncValidator(val) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$toast.loading(this.$t('validating'));
|
this.$toast.loading(this.$t('validating'));
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.$toast.clear();
|
this.$toast.clear();
|
||||||
resolve(/\d{6}/.test(val));
|
resolve(val === '1234');
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -24,15 +24,21 @@ exports[`renders demo correctly 1`] = `
|
|||||||
<div>
|
<div>
|
||||||
<form class="van-form">
|
<form class="van-form">
|
||||||
<div class="van-cell van-field">
|
<div class="van-cell van-field">
|
||||||
<div class="van-cell__title van-field__label"><span>手机号</span></div>
|
<div class="van-cell__title van-field__label"><span>文本</span></div>
|
||||||
<div class="van-cell__value van-field__value">
|
<div class="van-cell__value van-field__value">
|
||||||
<div class="van-field__body"><input type="text" name="phone" placeholder="手机号" class="van-field__control"></div>
|
<div class="van-field__body"><input type="text" name="pattern" placeholder="正则校验" class="van-field__control"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="van-cell van-field">
|
<div class="van-cell van-field">
|
||||||
<div class="van-cell__title van-field__label"><span>验证码</span></div>
|
<div class="van-cell__title van-field__label"><span>文本</span></div>
|
||||||
<div class="van-cell__value van-field__value">
|
<div class="van-cell__value van-field__value">
|
||||||
<div class="van-field__body"><input type="text" name="code" placeholder="验证码" class="van-field__control"></div>
|
<div class="van-field__body"><input type="text" name="validator" placeholder="函数校验" class="van-field__control"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="van-cell van-field">
|
||||||
|
<div class="van-cell__title van-field__label"><span>文本</span></div>
|
||||||
|
<div class="van-cell__value van-field__value">
|
||||||
|
<div class="van-field__body"><input type="text" name="asyncValidator" placeholder="异步函数校验" class="van-field__control"></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="margin: 16px 16px 0px;"><button type="submit" class="van-button van-button--info van-button--normal van-button--block van-button--round"><span class="van-button__text">
|
<div style="margin: 16px 16px 0px;"><button type="submit" class="van-button van-button--info van-button--normal van-button--block van-button--round"><span class="van-button__text">
|
||||||
|
@ -32,6 +32,33 @@ test('rules prop - execute order', async () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('rules prop - pattern', async () => {
|
||||||
|
const onFailed = jest.fn();
|
||||||
|
const wrapper = mountForm({
|
||||||
|
template: `
|
||||||
|
<van-form @failed="onFailed">
|
||||||
|
<van-field name="A" :rules="rules" value="123" />
|
||||||
|
<van-button native-type="submit" />
|
||||||
|
</van-form>
|
||||||
|
`,
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
rules: [{ pattern: /\d{6}/, message: 'foo' }],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onFailed,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
await submitForm(wrapper);
|
||||||
|
|
||||||
|
expect(onFailed).toHaveBeenCalledWith({
|
||||||
|
errors: [{ message: 'foo', name: 'A' }],
|
||||||
|
values: { A: '123' },
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test('rules prop - async validator', async () => {
|
test('rules prop - async validator', async () => {
|
||||||
const onFailed = jest.fn();
|
const onFailed = jest.fn();
|
||||||
const wrapper = mountForm({
|
const wrapper = mountForm({
|
||||||
|
Loading…
x
Reference in New Issue
Block a user