验证React的复杂形式。 第一部分

首先,您需要安装react-validation-boo组件,我假设您熟悉react并知道如何配置它。

npm install react-validation-boo

为了不多说,我将立即举一个小代码示例。

import React, {Component} from 'react'; import {connect, Form, Input, logger} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <Input type="text" name="name" /> {this.getError('name')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ( [ ['name', 'required'], ] ), middleware: logger })(MyForm); 


让我们分析一下这段代码。

让我们从connect函数开始,我们将验证规则和其他附加参数传递给它。 通过调用此方法,我们获得了一个新函数,该函数中传递了组件( MyForm ),以便它接收props中进行表单验证所需的必要方法。

在组件的render函数中,我们返回连接到验证规则的Form组件connect = {this.props.connect} 。 这是Form知道如何验证嵌套组件的必要设计。
<Input type =“ text” name =“ name” />我们将检查的输入字段,我们在规则属性中传递了验证规则以进行连接 。 在我们的情况下,该名称不能为空( 必需 )。

我们还通过了中间件:记录器进行连接 ,以查看控制台中的验证方式。

在组件的道具中 ,我们获得了一组功能:

  1. vBoo.isValid() -如果所有输入组件均已通过验证,则返回true
  2. vBoo.hasError(name) -如果具有name属性的组件无效,则返回true
  3. vBoo.getError(name) -对于具有name属性的组件,返回错误文本

现在,我们将逐步使其复杂化,首先将语言传递给connect ,以便我们可以根据语言来更改验证规则,还可以添加其他字段和验证规则。

 import React, {Component} from 'react'; import {connect, Form, Input, InputCheckbox} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('remember')}:</label> <InputCheckbox name="remember" value="yes" /> {this.getError('remember')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: (lang) => { let rules = [ [ ['name', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'] ]; rules.push(['remember', lang === 'ru' ? 'required': 'valid']); return rules; }, labels: (lang) => ({ name: '', email: ' ', remember: '' }), lang: 'ru' })(MyForm); 

在此示例中,必须安装俄文的记住复选框,这是必需的 ,但在其他情况下,该复选框始终有效。

我们还将函数标签(lang)传递给connect ,该函数以可读的形式返回字段的名称。

在组件的props中 ,有一个getLabel(name)函数,该函数返回传递给标签函数的值,或者如果没有该值,则返回name

VBoo核心组件


表单输入InputRadioInputCheckbox选择Textarea

 import React, {Component} from 'react'; import {connect, Form, Input, Select, InputRadio, InputCheckbox, Textarea} from 'react-validation-boo'; class MyForm extends Component { sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('gender')}:</label> <Select name="gender"> <option disabled> </option> <option value="1"></option> <option value="2"></option> </Select> {this.getError('gender')} </div> <div> <div>{this.props.vBoo.getLabel('familyStatus')}:</div> <div> <InputRadio name="familyStatus" value="1" checked /> <label></label> </div> <div> <InputRadio name="familyStatus" value="2" /> <label></label> </div> <div> <InputRadio name="familyStatus" value="3" /> <label></label> </div> {this.getError('familyStatus')} </div> <div> <label>{this.props.vBoo.getLabel('comment')}:</label> <Textarea name="comment"></Textarea> {this.getError('comment')} </div> <div> <label>{this.props.vBoo.getLabel('remember')}:</label> <InputCheckbox name="remember" value="yes" /> {this.getError('remember')} </div> <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ([ [ ['name', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'], [['gender', 'familyStatus', 'comment', 'remember'], 'valid'] ]), labels: () => ({ name: '', email: ' ', gender: '', familyStatus: ' ', comment: '', remember: '' }), lang: 'ru' })(MyForm); 

验证规则


让我们看看如何编写我们自己的验证规则。
为了编写规则,您必须创建一个将从验证程序类继承的类。

 import {validator} from 'react-validation-boo'; class myValidator extends validator { /** * name -  ,   label    * value -    * params -     3-    (rules) */ validate(name, value, params) { let lang = this.getLang(); let pattern = /^\d+$/; if(!pattern.test(value)) { let error = params.error || '   %name%   %value%'; error = error.replace('%name%', name); error = error.replace('%value%', value); this.addError(error); } } } export default myValidator; 

现在,将我们的验证器连接到表单。
 import myValidator from 'path/myValidator'; // ... export default connect({ rules: () => ([ [ 'name', 'required', { error: '%name%    ' } ], [ 'name', 'myValidator', { error: '   params.error' } ] ]), labels: () => ({ name: '' }), validators: { myValidator }, lang: 'ru' })(MyForm); 

为了不每次都注册所有验证规则,请创建一个单独的文件来注册它们,并连接其验证器:`import'file-validation`` 。 如果此表单有任何特殊规则,则验证器为:Object.assign({},`import'file-validation``,{...})

情境


考虑当我们需要根据对表单执行的操作来更改验证规则的情况。

默认情况下,我们在规则中有一个名为default的脚本,我们可以指定在哪种情况下执行此验证。

如果未指定脚本,则将对所有方案执行验证。

 rules = () => ([ [ 'name', 'required', { error: '%name%    ' } ], [ 'name', 'myValidator', { scenario: ['default', 'scenario1'] } ], [ 'email', 'email', { scenario: 'scenario1' } ] ]) 

该函数通过组件的props属性传递:

  1. vBoo.setScenario(场景) -设置场景脚本 ,如果我们一次有多个脚本处于活动状态,则可以是字符串或数组
  2. vBoo.getScenario() -返回当前脚本或脚本数组
  3. vBoo.hasScenario(名称) -是否立即安装此脚本, 名称字符串

让我们在表单中添加一个scenaries对象,该对象中将存储所有可能的脚本, true的脚本是活动的, false的不是。

以及将添加和删除脚本的addScenariesdeleteScenaries函数。

如果我们选择了“同居”或“婚姻”,那么我们将添加一个注释字段,并且很自然仅在这种情况下(即已婚方案)验证此字段。

如果设置了“高级”复选框,那么我们将添加其他必填字段,即脚本“ censing-addition ”。

 import React, {Component} from 'react'; import {connect, Form, Input, Select, InputRadio, InputCheckbox, Textarea} from 'react-validation-boo'; class MyForm extends Component { constructor() { super(); this.scenaries = { 'scenario-married': false, 'scenario-addition': false } } changeScenaries(addScenaries = [], deleteScenaries = []) { addScenaries.forEach(item => this.scenaries[item] = true); deleteScenaries.forEach(item => this.scenaries[item] = false); let scenario = Object.keys(this.scenaries) .reduce((result, item) => this.scenaries[item]? result.concat(item): result, []); this.props.vBoo.setScenario(scenario); } addScenaries = (m = []) => this.changeScenaries(m, []); deleteScenaries = (m = []) => this.changeScenaries([], m); sendForm = (event) => { event.preventDefault(); if(this.props.vBoo.isValid()) { console.log('       ', this.props.vBoo.getValues()); } else { console.log('   ', this.props.vBoo.getErrors()); } }; getError = (name) => { return this.props.vBoo.hasError(name) ? <div className="error">{this.props.vBoo.getError(name)}</div> : ''; }; changeFamilyStatus = (event) => { let val = event.target.value; if(val !== '1') { this.addScenaries(['scenario-married']) } else { this.deleteScenaries(['scenario-married']); } }; changeAddition = (event) => { let check = event.target.checked; if(check) { this.addScenaries(['scenario-addition']) } else { this.deleteScenaries(['scenario-addition']); } }; getCommentContent() { if(this.props.vBoo.hasScenario('scenario-married')) { return ( <div key="comment-content"> <label>{this.props.vBoo.getLabel('comment')}:</label> <Textarea name="comment"></Textarea> {this.getError('comment')} </div> ); } return ''; } getAdditionContent() { if(this.props.vBoo.hasScenario('scenario-addition')) { return ( <div key="addition-content"> <label>{this.props.vBoo.getLabel('place')}:</label> <Input type="text" name="place" /> {this.getError('place')} </div> ); } return ''; } render() { return <Form connect={this.props.vBoo.connect}> <div> <label>{this.props.vBoo.getLabel('name')}:</label> <Input type="text" name="name" /> {this.getError('name')} </div> <div> <label>{this.props.vBoo.getLabel('email')}:</label> <Input type="text" name="email" value="default@mail.ru" /> {this.getError('email')} </div> <div> <label>{this.props.vBoo.getLabel('gender')}:</label> <Select name="gender"> <option disabled> </option> <option value="1"></option> <option value="2"></option> </Select> {this.getError('gender')} </div> <div> <div>{this.props.vBoo.getLabel('familyStatus')}:</div> <div> <InputRadio name="familyStatus" value="1" checked onChange={this.changeFamilyStatus} /> <label></label> </div> <div> <InputRadio name="familyStatus" value="2" onChange={this.changeFamilyStatus} /> <label></label> </div> <div> <InputRadio name="familyStatus" value="3" onChange={this.changeFamilyStatus} /> <label></label> </div> {this.getError('familyStatus')} </div> {this.getCommentContent()} <div> <label>{this.props.vBoo.getLabel('addition')}:</label> <InputCheckbox name="addition" value="yes" onChange={this.changeAddition} /> {this.getError('addition')} </div> {this.getAdditionContent()} <button onClick={this.sendForm}> {this.props.vBoo.isValid() ? ' ': ' !!!'} </button> </Form> } } export default connect({ rules: () => ([ [ ['name', 'gender', 'familyStatus', 'email'], 'required', { error: '%name%    ' } ], ['email', 'email'], [ 'comment', 'required', { scenario: 'scenario-married' } ], ['addition', 'valid'], [ 'place', 'required', { scenario: 'scenario-addition' } ], ]), labels: () => ({ name: '', email: ' ', gender: '', familyStatus: ' ', comment: '', addition: '', place: '' }), lang: 'ru' })(MyForm); 

为了不使文章变得太大,我将继续在下一个文章中,在该文章中,我将介绍如何创建组件(例如,日历或inputSearch)并对其进行验证,以及如何与redux关联等等。

Source: https://habr.com/ru/post/zh-CN430312/


All Articles