简体   繁体   English

如何使用 React.JS 正确验证输入值?

[英]How to properly validate input values with React.JS?

I have a simple form.我有一个简单的表格。 All of the components and state are held in the Page component.所有的组件和状态都保存在 Page 组件中。 There are 2 display headers and 3 input fields.有 2 个显示标题和 3 个输入字段。 The first input is supposed to be text, and the second and third are supposed to be ints.第一个输入应该是文本,第二个和第三个应该是整数。 When the user inputs the wrong type of data, I want to have an error message pop up next to the input field.当用户输入错误类型的数据时,我希望在输入字段旁边弹出一条错误消息。 My questions relate to best practices in React.JS我的问题与 React.JS 中的最佳实践有关

Who decides that the value is in valid?谁决定该值有效? I suppose that the only job of the input field is to direct the value back to component holding the state, so does this mean that only Page can determine if a value is valid?我想输入字段的唯一工作是将值引导回保持状态的组件,所以这是否意味着只有 Page 可以确定值是否有效?

How should I then have the pop up appear?我应该如何让弹出窗口出现? Should Page have to trigger a new boolean state element that will be passed through perp that will tell Adaptive_Input to reveal the error message? Page 是否应该触发一个新的布尔状态元素,该元素将通过 perp 传递,告诉 Adaptive_Input 显示错误消息?

JSFiddle JSFiddle

JS: JS:

/**
 * @jsx React.DOM
 */
var Adaptive_Input = React.createClass({ 
    handle_change: function(){
        var new_text = this.refs.input.getDOMNode().value;
        this.props.on_Input_Change(new_text);
    },
    render: function(){
        return (
                <div className='adaptive_placeholder_input_container'>
                    <input 
                        className="adaptive_input"
                        type="text" 
                        required="required" 
                        onChange= {this.handle_change}
                        ref="input"
                    ></input>
                    <label
                        className="adaptive_placeholder"
                        alt={this.props.initial}
                        placeholder={this.props.focused}
                    ></label>
                </div>              
                );
    }
});

var Form = React.createClass({
    render: function(){
        return (
                <form>
                    <Adaptive_Input
                        initial={'Name Input'}
                        focused={'Name Input'}
                        on_Input_Change={this.props.handle_text_input}
                    />
                    <Adaptive_Input
                        initial={'Value 1'}
                        focused={'Value 1'}
                        on_Input_Change={this.props.handle_value_1_input}
                    />
                    <Adaptive_Input
                        initial={'Value 2'}
                        focused={'Value 2'}
                        on_Input_Change={this.props.handle_value_2_input}
                    />
                </form>
                );
    }
});

var Page = React.createClass({
    getInitialState: function(){
        return {
            Name : "No Name",
            Value_1 : '0',
            Value_2 : '0',
            Display_Value: '0'
        };
    },
    handle_text_input: function(new_text){
        this.setState({
                Name: new_text
            });
    },
    handle_value_1_input: function(new_value){
        console.log("===");
        var updated_display = parseInt(new_value) + parseInt(this.state.Value_2);
        updated_display = updated_display.toString();
        this.setState({
                Display_Value: updated_display 
            });
    },
    handle_value_2_input: function(new_value){
        var updated_display = parseInt(this.state.Value_1) + parseInt(new_value);
        updated_display = updated_display.toString();
        this.setState({
                Display_Value: updated_display
            });
    },
    render: function(){
        return(
                <div>
                    <h2>{this.state.Name}</h2>
                    <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
                    <Form
                        handle_text_input={this.handle_text_input}
                        handle_value_1_input = {this.handle_value_1_input}
                        handle_value_2_input = {this.handle_value_2_input}
                    />
                </div>
        );
    }
});

React.renderComponent(<Page />, document.body);

First, here is an example of what I'll mention below: http://jsbin.com/rixido/2/edit首先,这是我将在下面提到的示例: http : //jsbin.com/rixido/2/edit

How to properly validate input values with React.JS?如何使用 React.JS 正确验证输入值?

However you want.随你怎么便。 React is for rendering a data model. React 用于渲染数据模型。 The data model should know what is valid or not.数据模型应该知道什么是有效的,什么是无效的。 You can use Backbone models, JSON data, or anything you want to represent the data and it's error state.您可以使用 Backbone 模型、JSON 数据或任何您想要表示数据及其错误状态的东西。

More specifically:进一步来说:

React is generally agnostic towards your data. React 通常对您的数据不可知。 It's for rendering and dealing with events.它用于渲染和处理事件。

The rules to follow are:要遵循的规则是:

  1. elements can change their state.元素可以改变它们的状态。
  2. they cannot change props.他们不能改变道具。
  3. they can invoke a callback that will change top level props.他们可以调用一个回调来改变顶级道具。

How to decide if something should be a prop or a state?如何决定某物应该是道具还是状态? Consider this: would ANY part of your app other than the text field want to know that the value entered is bad?考虑一下:除了文本字段之外,您的应用程序的任何部分都想知道输入的值是错误的吗? If no, make it a state.如果不是,则将其设为状态。 If yes, it should be a prop.如果是,它应该是一个道具。

For example, if you wanted a separate view to render "You have 2 errors on this page."例如,如果您想要一个单独的视图来呈现“您在此页面上有 2 个错误”。 then your error would have to be known to a toplevel data model.那么顶级数据模型必须知道您的错误。

Where should that error live?该错误应该在哪里?
If your app was rendering Backbone models (for example), the model itself would have a validate() method and validateError property you could use.如果您的应用程序正在渲染 Backbone 模型(例如),模型本身将有一个 validate() 方法和您可以使用的 validateError 属性。 You could render other smart objects that could do the same.您可以渲染其他可以执行相同操作的智能对象。 React also says try to keep props to a minimum and generate the rest of the data. React 还说尽量减少 props 并生成其余的数据。 so if you had a validator (eg https://github.com/flatiron/revalidator ) then your validations could trickle down and any component could check props with it's matching validation to see if it's valid.因此,如果您有一个验证器(例如https://github.com/flatiron/revalidator ),那么您的验证可能会逐渐向下传递,并且任何组件都可以检查具有匹配验证的 props 以查看它是否有效。

It's largely up to you.这在很大程度上取决于你。

(I am personally using Backbone models and rendering them in React. I have a toplevel error alert that I show if there is an error anywhere, describing the error.) (我个人使用 Backbone 模型并在 React 中渲染它们。我有一个顶级错误警报,我会显示任何地方是否有错误,描述错误。)

You can use npm install --save redux-form您可以使用npm install --save redux-form

Im writing a simple email and submit button form, which validates email and submits form.我写了一个简单的电子邮件和提交按钮表单,它验证电子邮件并提交表单。 with redux-form, form by default runs event.preventDefault() on html onSubmit action.使用 redux-form,表单默认在 html onSubmit 操作上运行 event.preventDefault()。

import React, {Component} from 'react';
import {reduxForm} from 'redux-form';

class LoginForm extends Component {
  onSubmit(props) {
    //do your submit stuff
  }


  render() {
    const {fields: {email}, handleSubmit} = this.props;

    return (
      <form onSubmit={handleSubmit(this.onSubmit.bind(this))}>
        <input type="text" placeholder="Email"
               className={`form-control ${email.touched && email.invalid ? 'has-error' : '' }`}
          {...email}
        />
          <span className="text-help">
            {email.touched ? email.error : ''}
          </span>
        <input type="submit"/>
      </form>
    );
  }
}

function validation(values) {
  const errors = {};
  const emailPattern = /(.+)@(.+){2,}\.(.+){2,}/;
  if (!emailPattern.test(values.email)) {
    errors.email = 'Enter a valid email';
  }

  return errors;
}

LoginForm = reduxForm({
  form: 'LoginForm',
  fields: ['email'],
  validate: validation
}, null, null)(LoginForm);

export default LoginForm;

I have written This library which allows you to wrap your form element components, and lets you define your validators in the format :-我编写了这个库,它允许您包装表单元素组件,并允许您以以下格式定义验证器:-

<Validation group="myGroup1"
    validators={[
            {
             validator: (val) => !validator.isEmpty(val),
             errorMessage: "Cannot be left empty"
            },...
        }]}>
            <TextField value={this.state.value}
                       className={styles.inputStyles}
                       onChange={
                        (evt)=>{
                          console.log("you have typed: ", evt.target.value);
                        }
                       }/>
</Validation>

Your jsfiddle does not work anymore.你的 jsfiddle 不再工作了。 I've fixed it: http://jsfiddle.net/tkrotoff/bgC6E/40/ using React 16 and ES6 classes.我已经修复了它: http : //jsfiddle.net/tkrotoff/bgC6E/40/使用 React 16 和 ES6 类。

class Adaptive_Input extends React.Component {
  handle_change(e) {
    var new_text = e.currentTarget.value;
    this.props.on_Input_Change(new_text);
  }

  render() {
    return (
      <div className="adaptive_placeholder_input_container">
        <input
          className="adaptive_input"
          type="text"
          required="required"
          onChange={this.handle_change.bind(this)} />
        <label
          className="adaptive_placeholder"
          alt={this.props.initial}
          placeholder={this.props.focused} />
      </div>
    );
  }
}

class Form extends React.Component {
  render() {
    return (
      <form>
        <Adaptive_Input
          initial={'Name Input'}
          focused={'Name Input'}
          on_Input_Change={this.props.handle_text_input} />

        <Adaptive_Input
          initial={'Value 1'}
          focused={'Value 1'}
          on_Input_Change={this.props.handle_value_1_input} />

        <Adaptive_Input
          initial={'Value 2'}
          focused={'Value 2'}
          on_Input_Change={this.props.handle_value_2_input} />
      </form>
    );
  }
}

class Page extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      Name: 'No Name',
      Value_1: '0',
      Value_2: '0',
      Display_Value: '0'
    };
  }

  handle_text_input(new_text) {
    this.setState({
      Name: new_text
    });
  }

  handle_value_1_input(new_value) {
    new_value = parseInt(new_value);
    var updated_display = new_value + parseInt(this.state.Value_2);
    updated_display = updated_display.toString();
    this.setState({
      Value_1: new_value,
      Display_Value: updated_display
    });
  }

  handle_value_2_input(new_value) {
    new_value = parseInt(new_value);
    var updated_display = parseInt(this.state.Value_1) + new_value;
    updated_display = updated_display.toString();
    this.setState({
      Value_2: new_value,
      Display_Value: updated_display
    });
  }

  render() {
    return(
      <div>
        <h2>{this.state.Name}</h2>
        <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>
        <Form
          handle_text_input={this.handle_text_input.bind(this)}
          handle_value_1_input={this.handle_value_1_input.bind(this)}
          handle_value_2_input={this.handle_value_2_input.bind(this)}
        />
      </div>
    );
  }
}

ReactDOM.render(<Page />, document.getElementById('app'));

And now the same code hacked with form validation thanks to this library: https://github.com/tkrotoff/react-form-with-constraints => http://jsfiddle.net/tkrotoff/k4qa4heg/现在,由于这个库,同样的代码通过表单验证被破解: https : //github.com/tkrotoff/react-form-with-constraints => http://jsfiddle.net/tkrotoff/k4qa4heg/

http://jsfiddle.net/tkrotoff/k4qa4heg/

const { FormWithConstraints, FieldFeedbacks, FieldFeedback } = ReactFormWithConstraints;

class Adaptive_Input extends React.Component {
  static contextTypes = {
    form: PropTypes.object.isRequired
  };

  constructor(props) {
    super(props);

    this.state = {
      field: undefined
    };

    this.fieldWillValidate = this.fieldWillValidate.bind(this);
    this.fieldDidValidate = this.fieldDidValidate.bind(this);
  }

  componentWillMount() {
    this.context.form.addFieldWillValidateEventListener(this.fieldWillValidate);
    this.context.form.addFieldDidValidateEventListener(this.fieldDidValidate);
  }

  componentWillUnmount() {
    this.context.form.removeFieldWillValidateEventListener(this.fieldWillValidate);
    this.context.form.removeFieldDidValidateEventListener(this.fieldDidValidate);
  }

  fieldWillValidate(fieldName) {
    if (fieldName === this.props.name) this.setState({field: undefined});
  }

  fieldDidValidate(field) {
    if (field.name === this.props.name) this.setState({field});
  }

  handle_change(e) {
    var new_text = e.currentTarget.value;
    this.props.on_Input_Change(e, new_text);
  }

  render() {
    const { field } = this.state;
    let className = 'adaptive_placeholder_input_container';
    if (field !== undefined) {
      if (field.hasErrors()) className += ' error';
      if (field.hasWarnings()) className += ' warning';
    }

    return (
      <div className={className}>
        <input
          type={this.props.type}
          name={this.props.name}
          className="adaptive_input"
          required
          onChange={this.handle_change.bind(this)} />
        <label
          className="adaptive_placeholder"
          alt={this.props.initial}
          placeholder={this.props.focused} />
      </div>
    );
  }
}

class Form extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      Name: 'No Name',
      Value_1: '0',
      Value_2: '0',
      Display_Value: '0'
    };
  }

  handle_text_input(e, new_text) {
    this.form.validateFields(e.currentTarget);

    this.setState({
      Name: new_text
    });
  }

  handle_value_1_input(e, new_value) {
    this.form.validateFields(e.currentTarget);

    if (this.form.isValid()) {
      new_value = parseInt(new_value);
      var updated_display = new_value + parseInt(this.state.Value_2);
      updated_display = updated_display.toString();
      this.setState({
        Value_1: new_value,
        Display_Value: updated_display
      });
    }
    else {
      this.setState({
        Display_Value: 'Error'
      });
    }
  }

  handle_value_2_input(e, new_value) {
    this.form.validateFields(e.currentTarget);

    if (this.form.isValid()) {
      new_value = parseInt(new_value);
      var updated_display = parseInt(this.state.Value_1) + new_value;
      updated_display = updated_display.toString();
      this.setState({
        Value_2: new_value,
        Display_Value: updated_display
      });
    }
    else {
      this.setState({
        Display_Value: 'Error'
      });
    }
  }

  render() {
    return(
      <div>
        <h2>Name: {this.state.Name}</h2>
        <h2>Value 1 + Value 2 = {this.state.Display_Value}</h2>

        <FormWithConstraints ref={form => this.form = form} noValidate>
          <Adaptive_Input
            type="text"
            name="name_input"
            initial={'Name Input'}
            focused={'Name Input'}
            on_Input_Change={this.handle_text_input.bind(this)} />
          <FieldFeedbacks for="name_input">
            <FieldFeedback when="*" error />
            <FieldFeedback when={value => !/^\w+$/.test(value)} warning>Should only contain alphanumeric characters</FieldFeedback>
          </FieldFeedbacks>

          <Adaptive_Input
            type="number"
            name="value_1_input"
            initial={'Value 1'}
            focused={'Value 1'}
            on_Input_Change={this.handle_value_1_input.bind(this)} />
          <FieldFeedbacks for="value_1_input">
            <FieldFeedback when="*" />
          </FieldFeedbacks>

          <Adaptive_Input
            type="number"
            name="value_2_input"
            initial={'Value 2'}
            focused={'Value 2'}
            on_Input_Change={this.handle_value_2_input.bind(this)} />
          <FieldFeedbacks for="value_2_input">
            <FieldFeedback when="*" />
          </FieldFeedbacks>
        </FormWithConstraints>
      </div>
    );
  }
}

ReactDOM.render(<Form />, document.getElementById('app'));

The proposed solution here is hackish as I've tried to keep it close to the original jsfiddle.这里建议的解决方案是hackish,因为我试图让它接近原始的jsfiddle。 For proper form validation with react-form-with-constraints, check https://github.com/tkrotoff/react-form-with-constraints#examples要使用 react-form-with-constraints 进行正确的表单验证,请检查https://github.com/tkrotoff/react-form-with-constraints#examples

Use onChange={this.handleChange.bind(this, "name") method and value={this.state.fields["name"]} on input text field and below that create span element to show error, see the below example.在输入文本字段和下方使用onChange={this.handleChange.bind(this, "name")方法和value={this.state.fields["name"]}创建跨度元素以显示错误,请参阅下面的示例.

export default class Form extends Component {

  constructor(){
    super()
    this.state ={
       fields: {
         name:'',
         email: '',
         message: ''
       },
       errors: {},
       disabled : false
    }
  }

  handleValidation(){
       let fields = this.state.fields;
       let errors = {};
       let formIsValid = true;

       if(!fields["name"]){
          formIsValid = false;
          errors["name"] = "Name field cannot be empty";
       }

       if(typeof fields["name"] !== "undefined" && !fields["name"] === false){
          if(!fields["name"].match(/^[a-zA-Z]+$/)){
             formIsValid = false;
             errors["name"] = "Only letters";
          }
       }

       if(!fields["email"]){
          formIsValid = false;
          errors["email"] = "Email field cannot be empty";
       }

       if(typeof fields["email"] !== "undefined" && !fields["email"] === false){
          let lastAtPos = fields["email"].lastIndexOf('@');
          let lastDotPos = fields["email"].lastIndexOf('.');

          if (!(lastAtPos < lastDotPos && lastAtPos > 0 && fields["email"].indexOf('@@') === -1 && lastDotPos > 2 && (fields["email"].length - lastDotPos) > 2)) {
             formIsValid = false;
             errors["email"] = "Email is not valid";
           }
      }

      if(!fields["message"]){
         formIsValid = false;
         errors["message"] = " Message field cannot be empty";
      }

      this.setState({errors: errors});
      return formIsValid;
  }

  handleChange(field, e){
      let fields = this.state.fields;
      fields[field] = e.target.value;
      this.setState({fields});
  }

  handleSubmit(e){
      e.preventDefault();
      if(this.handleValidation()){
          console.log('validation successful')
        }else{
          console.log('validation failed')
        }
  }

  render(){
    return (
      <form onSubmit={this.handleSubmit.bind(this)} method="POST">
          <div className="row">
            <div className="col-25">
                <label htmlFor="name">Name</label>
            </div>
            <div className="col-75">
                <input type="text" placeholder="Enter Name"  refs="name" onChange={this.handleChange.bind(this, "name")} value={this.state.fields["name"]}/>
                <span style={{color: "red"}}>{this.state.errors["name"]}</span>
            </div>
          </div>
          <div className="row">
            <div className="col-25">
              <label htmlFor="exampleInputEmail1">Email address</label>
            </div>
            <div className="col-75">
                <input type="email" placeholder="Enter Email" refs="email" aria-describedby="emailHelp" onChange={this.handleChange.bind(this, "email")} value={this.state.fields["email"]}/>
                <span style={{color: "red"}}>{this.state.errors["email"]}</span>
            </div>
          </div>
          <div className="row">
            <div className="col-25">
                <label htmlFor="message">Message</label>
            </div>
            <div className="col-75">
                <textarea type="text" placeholder="Enter Message" rows="5" refs="message" onChange={this.handleChange.bind(this, "message")} value={this.state.fields["message"]}></textarea>
                <span style={{color: "red"}}>{this.state.errors["message"]}</span>
            </div>
          </div>
          <div className="row">
            <button type="submit" disabled={this.state.disabled}>{this.state.disabled ? 'Sending...' : 'Send'}</button>
          </div>
      </form>
    )
  }
}

I have used redux-form and formik in the past, and recently React introduced Hook, and i have built a custom hook for it.我过去使用过 redux-form 和 formik,最近 React 引入了 Hook,我为它构建了一个自定义钩子。 Please check it out and see if it make your form validation much easier.请检查一下,看看它是否使您的表单验证更容易。

Github: https://github.com/bluebill1049/react-hook-form Github: https : //github.com/bluebill1049/react-hook-form

Website: http://react-hook-form.now.sh网站: http : //react-hook-form.now.sh

with this approach, you are no longer doing controlled input too.使用这种方法,您也不再进行受控输入。

example below:下面的例子:

import React from 'react'
import useForm from 'react-hook-form'

function App() {
  const { register, handleSubmit, errors } = useForm() // initialise the hook
  const onSubmit = (data) => { console.log(data) } // callback when validation pass

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      <input name="firstname" ref={register} /> {/* register an input */}

      <input name="lastname" ref={register({ required: true })} /> {/* apply required validation */}
      {errors.lastname && 'Last name is required.'} {/* error message */}

      <input name="age" ref={register({ pattern: /\d+/ })} /> {/* apply a Refex validation */}
      {errors.age && 'Please enter number for age.'} {/* error message */}

      <input type="submit" />
    </form>
  )
}

I recently spent a week studying lot of solutions to validate my forms in an app.我最近花了一个星期研究了很多解决方案来验证我在应用程序中的表单。 I started with all the most stared one but I couldn't find one who was working as I was expected.我从所有最受关注的人开始,但我找不到像我预期的那样工作的人。 After few days, I became quite frustrated until i found a very new and amazing plugin: https://github.com/kettanaito/react-advanced-form几天后,我变得非常沮丧,直到我发现了一个非常新且令人惊叹的插件: https : //github.com/kettanaito/react-advanced-form

The developper is very responsive and his solution, after my research, merit to become the most stared one from my perspective.开发人员非常敏感,经过我的研究,他的解决方案值得成为我认为最受关注的解决方案。 I hope it could help and you'll appreciate.我希望它可以帮助你,你会感激的。

另一个解决相同问题的方法 - npm 上的form-container

Sometimes you can have multiple fields with similar validation in your application.有时,您的应用程序中可以有多个具有类似验证的字段。 In such a case I recommend to create common component field where you keep this validation.在这种情况下,我建议创建公共组件字段,您可以在其中保留此验证。

For instance, let's assume that you have mandatory text input in a few places in your application.例如,假设您在应用程序的几个地方有强制性的文本输入。 You can create a TextInput component:您可以创建一个 TextInput 组件:

constructor(props) {
    super(props); 
    this.state = {
        touched: false, error: '', class: '', value: ''
    }
}

onValueChanged = (event) => {
    let [error, validClass, value] = ["", "", event.target.value];

    [error, validClass] = (!value && this.props.required) ? 
        ["Value cannot be empty", "is-invalid"] : ["", "is-valid"]

    this.props.onChange({value: value, error: error});

    this.setState({
        touched: true,
        error: error,
        class: validClass,
        value: value
    })
}

render() {
    return (
        <div>
            <input type="text"
                value={this.props.value}
                onChange={this.onValueChanged}
                className={"form-control " + this.state.class}
                id="{this.props.id}"
                placeholder={this.props.placeholder} />
            {this.state.error ?
                <div className="invalid-feedback">
                    {this.state.error}
                </div> : null
            }
        </div>
    )
}

And then you can use such a component anywhere in your application:然后你可以在你的应用程序的任何地方使用这样的组件:

constructor(props) {
    super(props);
    this.state = {
        user: {firstName: '', lastName: ''},
        formState: {
            firstName: { error: '' },
            lastName: { error: '' }
        }
    }
}

onFirstNameChange = (model) => {
    let user = this.state.user;
    user.firstName = model.value;

    this.setState({
        user: user,
        formState: {...this.state.formState, firstName: { error: model.error }}
    })
}

onLastNameChange = (model) => {
    let user = this.state.user;
    user.lastName = model.value;

    this.setState({
        user: user,
        formState: {...this.state.formState, lastName: { error: model.error }}
    })
}


onSubmit = (e) => {
   // submit logic
}


render() {
    return (
        <form onSubmit={this.onSubmit}>
            <TextInput id="input_firstName"
                value={this.state.user.firstName}
                onChange={this.onFirstNameChange}
                required = {true}
                placeholder="First name" />

            <TextInput id="input_lastName"
                value={this.state.user.lastName}
                onChange={this.onLastNameChange}
                required = {true}
                placeholder="Last name" />

            {this.state.formState.firstName.error || this.state.formState.lastName.error ?
                <button type="submit" disabled className="btn btn-primary margin-left disabled">Save</button>
                : <button type="submit" className="btn btn-primary margin-left">Save</button>
            }

        </form>
    )
}

Benefits:好处:

  • You don't repeat your validation logic你不要重复你的验证逻辑
  • Less code in your forms - it is more readable表单中的代码更少 - 更具可读性
  • Other common input logic can be kept in component其他常见的输入逻辑可以保留在组件中
  • You follow React rule that component should be as dumb as possible你遵循 React 规则,组件应该尽可能的愚蠢

Ref.参考https://webfellas.tech/#/article/5 https://webfellas.tech/#/article/5

I think https://medium.com/@krzakmarek88/complex-form-validation-in-react-hooks-cb07367196b9 validation model can be helpful. 我认为https://medium.com/@krzakmarek88/complex-form-validation-in-react-hooks-cb07367196b9验证模型可能会有所帮助。 You build once Components and you can use them any times for many forms. 您只需构建一次组件,就可以随时将它们用于多种表单。 Only you have to build dedicated form model for each form. 只有您必须为每个表单构建专用的表单模型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM