Element-React From 表單

2020-10-16 11:04 更新

由輸入框、選擇器、單選框、多選框等控件組成,用以收集、校驗(yàn)、提交數(shù)據(jù)

典型表單

包括各種表單項(xiàng),比如輸入框、選擇器、開關(guān)、單選框、多選框等。

在 Form 組件中,每一個(gè)表單域由一個(gè) Form-Item 組件構(gòu)成,表單域中可以放置各種類型的表單控件,包括 Input、Select、Checkbox、Radio、Switch、DatePicker、TimePicker

constructor(props) {
  super(props);


  this.state = {
    form: {
      name: '',
      region: '',
      date1: null,
      date2: null,
      delivery: false,
      type: [],
      resource: '',
      desc: ''
    }
  };
}


onSubmit(e) {
  e.preventDefault();
}


onChange(key, value) {
  this.state.form[key] = value;
  this.forceUpdate();
}


render() {
  return (
    <Form model={this.state.form} labelWidth="80" onSubmit={this.onSubmit.bind(this)}>
      <Form.Item label="活動(dòng)名稱">
        <Input value={this.state.form.name} onChange={this.onChange.bind(this, 'name')}></Input>
      </Form.Item>
      <Form.Item label="活動(dòng)區(qū)域">
        <Select value={this.state.form.region} placeholder="請選擇活動(dòng)區(qū)域">
          <Select.Option label="區(qū)域一" value="shanghai"></Select.Option>
          <Select.Option label="區(qū)域二" value="beijing"></Select.Option>
        </Select>
      </Form.Item>
      <Form.Item label="活動(dòng)時(shí)間">
        <Layout.Col span="11">
          <Form.Item prop="date1" labelWidth="0px">
            <DatePicker
              value={this.state.form.date1}
              placeholder="選擇日期"
              onChange={this.onChange.bind(this, 'date1')}
            />
          </Form.Item>
        </Layout.Col>
        <Layout.Col className="line" span="2">-</Layout.Col>
        <Layout.Col span="11">
          <Form.Item prop="date2" labelWidth="0px">
            <TimePicker
              value={this.state.form.date2}
              selectableRange="18:30:00 - 20:30:00"
              placeholder="選擇時(shí)間"
              onChange={this.onChange.bind(this, 'date2')}
            />
          </Form.Item>
        </Layout.Col>
      </Form.Item>
      <Form.Item label="即時(shí)配送">
        <Switch
          onText=""
          offText=""
          value={this.state.form.delivery}
          onChange={this.onChange.bind(this, 'delivery')}
        />
      </Form.Item>
      <Form.Item label="活動(dòng)性質(zhì)">
        <Checkbox.Group value={this.state.form.type} onChange={this.onChange.bind(this, 'type')}>
          <Checkbox label="美食/餐廳線上活動(dòng)" name="type"></Checkbox>
          <Checkbox label="地推活動(dòng)" name="type"></Checkbox>
          <Checkbox label="線下主題活動(dòng)" name="type"></Checkbox>
          <Checkbox label="單純品牌曝光" name="type"></Checkbox>
        </Checkbox.Group>
      </Form.Item>
      <Form.Item label="特殊資源">
        <Radio.Group value={this.state.form.resource}>
          <Radio value="線上品牌商贊助"></Radio>
          <Radio value="線下場地免費(fèi)"></Radio>
        </Radio.Group>
      </Form.Item>
      <Form.Item label="活動(dòng)形式">
        <Input type="textarea" value={this.state.form.desc} onChange={this.onChange.bind(this, 'desc')}></Input>
      </Form.Item>
      <Form.Item>
        <Button type="primary" nativeType="submit">立即創(chuàng)建</Button>
        <Button>取消</Button>
      </Form.Item>
    </Form>
  )
}

行內(nèi)表單

當(dāng)垂直方向空間受限且表單較簡單時(shí),可以在一行內(nèi)放置表單。

Form 組件的 type 屬性可以控制表單的類型,當(dāng)設(shè)為 inline 時(shí)可以讓表單域變?yōu)樾袃?nèi)的表單域

constructor(props) {
  super(props);


  this.state = {
    form: {
      user: '',
      region: ''
    }
  };
}


onSubmit(e) {
  e.preventDefault();


  console.log('submit!');
}


onChange(key, value) {
  this.setState({
    form: Object.assign(this.state.form, { [key]: value })
  });
}


render() {
  return (
    <Form inline={true} model={this.state.form} onSubmit={this.onSubmit.bind(this)} className="demo-form-inline">
      <Form.Item>
        <Input value={this.state.form.user} placeholder="審批人" onChange={this.onChange.bind(this, 'user')}></Input>
      </Form.Item>
      <Form.Item>
        <Select value={this.state.form.region} placeholder="活動(dòng)區(qū)域">
          <Select.Option label="區(qū)域一" value="shanghai"></Select.Option>
          <Select.Option label="區(qū)域二" value="beijing"></Select.Option>
        </Select>
      </Form.Item>
      <Form.Item>
        <Button nativeType="submit" type="primary">查詢</Button>
      </Form.Item>
    </Form>
  )
}

對齊方式

根據(jù)具體目標(biāo)和制約因素,選擇最佳的標(biāo)簽對齊方式。

通過設(shè)置 labelPosition 屬性可以改變表單域標(biāo)簽的位置,可選值為 top、left,當(dāng)設(shè)為 top 時(shí)標(biāo)簽會(huì)置于表單域的頂部

constructor(props) {
  super(props);


  this.state = {
    labelPosition: 'right',
    form: {
      name: '',
      region: '',
      type: ''
    }
  };
}


onPositionChange(value) {
  this.setState({ labelPosition: value });
}


onChange(key, value) {
  this.setState({
    form: Object.assign(this.state.form, { [key]: value })
  });
}


render() {
  return (
    <div>
      <Radio.Group size="small" value={this.state.labelPosition} onChange={this.onPositionChange.bind(this)}>
        <Radio.Button value="left">左對齊</Radio.Button>
        <Radio.Button value="right">右對齊</Radio.Button>
        <Radio.Button value="top">頂部對齊</Radio.Button>
      </Radio.Group>
      <div style={{ margin: 20 }}></div>
      <Form labelPosition={this.state.labelPosition} labelWidth="100" model={this.state.form} className="demo-form-stacked">
        <Form.Item label="名稱">
          <Input value={this.state.form.name} onChange={this.onChange.bind(this, 'name')}></Input>
        </Form.Item>
        <Form.Item label="活動(dòng)區(qū)域">
          <Input value={this.state.form.region} onChange={this.onChange.bind(this, 'region')}></Input>
        </Form.Item>
        <Form.Item label="活動(dòng)展開形式">
          <Input value={this.state.form.type} onChange={this.onChange.bind(this, 'type')}></Input>
        </Form.Item>
      </Form>
    </div>
  )
}

表單驗(yàn)證

在防止用戶犯錯(cuò)的前提下,盡可能讓用戶更早地發(fā)現(xiàn)并糾正錯(cuò)誤。 Form 組件提供了表單驗(yàn)證的功能,只需要通過 rule 屬性傳入約定的驗(yàn)證規(guī)則,并 Form-Item 的 prop 屬相設(shè)置為需校驗(yàn)的字段名即可。校驗(yàn)規(guī)則參見 async-validator

constructor(props) {
  super(props);


  this.state = {
    form: {
      name: '',
      region: '',
      date1: null,
      date2: null,
      delivery: false,
      type: [],
      resource: '',
      desc: ''
    },
    rules: {
      name: [
        { required: true, message: '請輸入活動(dòng)名稱', trigger: 'blur' }
      ],
      region: [
        { required: true, message: '請選擇活動(dòng)區(qū)域', trigger: 'change' }
      ],
      date1: [
        { type: 'date', required: true, message: '請選擇日期', trigger: 'change' }
      ],
      date2: [
        { type: 'date', required: true, message: '請選擇時(shí)間', trigger: 'change' }
      ],
      type: [
        { type: 'array', required: true, message: '請至少選擇一個(gè)活動(dòng)性質(zhì)', trigger: 'change' }
      ],
      resource: [
        { required: true, message: '請選擇活動(dòng)資源', trigger: 'change' }
      ],
      desc: [
        { required: true, message: '請?zhí)顚懟顒?dòng)形式', trigger: 'blur' }
      ]
    }
  };
}


handleSubmit(e) {
  e.preventDefault();


  this.refs.form.validate((valid) => {
    if (valid) {
      alert('submit!');
    } else {
      console.log('error submit!!');
      return false;
    }
  });
}


handleReset(e) {
  e.preventDefault();


  this.refs.form.resetFields();
}


onChange(key, value) {
  this.setState({
    form: Object.assign({}, this.state.form, { [key]: value })
  });
}


render() {
  return (
    <Form ref="form" model={this.state.form} rules={this.state.rules} labelWidth="80" className="demo-ruleForm">
      <Form.Item label="活動(dòng)名稱" prop="name">
        <Input value={this.state.form.name} onChange={this.onChange.bind(this, 'name')}></Input>
      </Form.Item>
      <Form.Item label="活動(dòng)區(qū)域" prop="region">
        <Select value={this.state.form.region} placeholder="請選擇活動(dòng)區(qū)域" onChange={this.onChange.bind(this, 'region')}>
          <Select.Option label="區(qū)域一" value="shanghai"></Select.Option>
          <Select.Option label="區(qū)域二" value="beijing"></Select.Option>
        </Select>
      </Form.Item>
      <Form.Item label="活動(dòng)時(shí)間" required={true}>
        <Layout.Col span="11">
          <Form.Item prop="date1" labelWidth="0px">
            <DatePicker
              value={this.state.form.date1}
              placeholder="選擇日期"
              onChange={this.onChange.bind(this, 'date1')}
            />
          </Form.Item>
        </Layout.Col>
        <Layout.Col className="line" span="2">-</Layout.Col>
        <Layout.Col span="11">
          <Form.Item prop="date2" labelWidth="0px">
            <TimePicker
              value={this.state.form.date2}
              selectableRange="18:30:00 - 20:30:00"
              placeholder="選擇時(shí)間"
              onChange={this.onChange.bind(this, 'date2')}
            />
          </Form.Item>
        </Layout.Col>
      </Form.Item>
      <Form.Item label="即時(shí)配送" prop="delivery">
        <Switch value={this.state.form.delivery} onChange={this.onChange.bind(this, 'delivery')}></Switch>
      </Form.Item>
      <Form.Item label="活動(dòng)性質(zhì)" prop="type">
        <Checkbox.Group value={this.state.form.type} onChange={this.onChange.bind(this, 'type')}>
          <Checkbox label="美食/餐廳線上活動(dòng)" name="type"></Checkbox>
          <Checkbox label="地推活動(dòng)" name="type"></Checkbox>
          <Checkbox label="線下主題活動(dòng)" name="type"></Checkbox>
          <Checkbox label="單純品牌曝光" name="type"></Checkbox>
        </Checkbox.Group>
      </Form.Item>
      <Form.Item label="特殊資源" prop="resource">
        <Radio.Group value={this.state.form.resource} onChange={this.onChange.bind(this, 'resource')}>
          <Radio value="線上品牌商贊助"></Radio>
          <Radio value="線下場地免費(fèi)"></Radio>
        </Radio.Group>
      </Form.Item>
      <Form.Item label="活動(dòng)形式" prop="desc">
        <Input type="textarea" value={this.state.form.desc} onChange={this.onChange.bind(this, 'desc')}></Input>
      </Form.Item>
      <Form.Item>
        <Button type="primary" onClick={this.handleSubmit.bind(this)}>立即創(chuàng)建</Button>
        <Button onClick={this.handleReset.bind(this)}>重置</Button>
      </Form.Item>
    </Form>
  )
}

自定義校驗(yàn)規(guī)則

這個(gè)例子中展示了如何使用自定義驗(yàn)證規(guī)則來完成密碼的二次驗(yàn)證

constructor(props) {
  super(props);


  this.state = {
    form: {
      pass: '',
      checkPass: '',
      age: ''
    },
    rules: {
      pass: [
        { required: true, message: '請輸入密碼', trigger: 'blur' },
        { validator: (rule, value, callback) => {
          if (value === '') {
            callback(new Error('請輸入密碼'));
          } else {
            if (this.state.form.checkPass !== '') {
              this.refs.form.validateField('checkPass');
            }
            callback();
          }
        } }
      ],
      checkPass: [
        { required: true, message: '請?jiān)俅屋斎朊艽a', trigger: 'blur' },
        { validator: (rule, value, callback) => {
          if (value === '') {
            callback(new Error('請?jiān)俅屋斎朊艽a'));
          } else if (value !== this.state.form.pass) {
            callback(new Error('兩次輸入密碼不一致!'));
          } else {
            callback();
          }
        } }
      ],
      age: [
        { required: true, message: '請?zhí)顚懩挲g', trigger: 'blur' },
        { validator: (rule, value, callback) => {
          var age = parseInt(value, 10);


          setTimeout(() => {
            if (!Number.isInteger(age)) {
              callback(new Error('請輸入數(shù)字值'));
            } else{
              if (age < 18) {
                callback(new Error('必須年滿18歲'));
              } else {
                callback();
              }
            }
          }, 1000);
        }, trigger: 'change' }
      ]
    }
  };
}


handleSubmit(e) {
  e.preventDefault();


  this.refs.form.validate((valid) => {
    if (valid) {
      alert('submit!');
    } else {
      console.log('error submit!!');
      return false;
    }
  });
}


handleReset(e) {
  e.preventDefault();


  this.refs.form.resetFields();
}


onChange(key, value) {
  this.setState({
    form: Object.assign({}, this.state.form, { [key]: value })
  });
}


render() {
  return (
    <Form ref="form" model={this.state.form} rules={this.state.rules} labelWidth="100" className="demo-ruleForm">
      <Form.Item label="密碼" prop="pass">
        <Input type="password" value={this.state.form.pass} onChange={this.onChange.bind(this, 'pass')} autoComplete="off" />
      </Form.Item>
      <Form.Item label="確認(rèn)密碼" prop="checkPass">
        <Input type="password" value={this.state.form.checkPass} onChange={this.onChange.bind(this, 'checkPass')} autoComplete="off" />
      </Form.Item>
      <Form.Item label="年齡" prop="age">
        <Input value={this.state.form.age} onChange={this.onChange.bind(this, 'age')}></Input>
      </Form.Item>
      <Form.Item>
        <Button type="primary" onClick={this.handleSubmit.bind(this)}>提交</Button>
        <Button onClick={this.handleReset.bind(this)}>重置</Button>
      </Form.Item>
    </Form>
  )
}

動(dòng)態(tài)增減表單項(xiàng)

除了在 Form 組件上一次性傳遞所有的驗(yàn)證規(guī)則外還可以在單個(gè)的表單域上傳遞屬性的驗(yàn)證規(guī)則

constructor(props) {
  super(props);


  this.state = {
    form: {
      domains: [{
        key: 1,
        value: ''
      }],
      email: ''
    },
    rules: {
      email: [
        { required: true, message: '請輸入郵箱地址', trigger: 'blur' },
        { type: 'email', message: '請輸入正確的郵箱地址', trigger: 'blur,change' }
      ]
    }
  };
}


handleSubmit(e) {
  e.preventDefault();


  this.refs.form.validate((valid) => {
    if (valid) {
      alert('submit!');
    } else {
      console.log('error submit!!');
      return false;
    }
  });
}


removeDomain(item, e) {
  var index = this.state.form.domains.indexOf(item);


  if (index !== -1) {
    this.state.form.domains.splice(index, 1);
    this.forceUpdate();
  }


  e.preventDefault();
}


addDomain(e) {
  e.preventDefault();


  this.state.form.domains.push({
    key: this.state.form.domains.length,
    value: ''
  });


  this.forceUpdate();
}


onEmailChange(value) {
  this.setState({
    form: Object.assign({}, this.state.form, { email: value})
  });
}


onDomainChange(index, value) {
  this.state.form.domains[index].value = value;
  this.forceUpdate();
}


render() {
  return (
    <Form ref="form" model={this.state.form} rules={this.state.rules} labelWidth="100" className="demo-dynamic">
      <Form.Item prop="email" label="郵箱">
        <Input value={this.state.form.email} onChange={this.onEmailChange.bind(this)}></Input>
      </Form.Item>
      {
        this.state.form.domains.map((domain, index) => {
          return (
            <Form.Item
              key={index}
              label={`域名${index}`}
              prop={`domains:${index}`}
              rules={{
                type: 'object', required: true,
                fields: {
                  value: { required: true, message: '域名不能為空', trigger: 'blur' }
                }
              }}
            >
              <Input value={domain.value} onChange={this.onDomainChange.bind(this, index)}></Input>
              <Button onClick={this.removeDomain.bind(this, domain)}>刪除</Button>
            </Form.Item>
          )
        })
      }
      <Form.Item>
        <Button type="primary" onClick={this.handleSubmit.bind(this)}>提交</Button>
        <Button onClick={this.addDomain.bind(this)}>新增域名</Button>
      </Form.Item>
    </Form>
  )
}

Form Attributes

參數(shù) 說明 類型 可選值 默認(rèn)值
model 表單數(shù)據(jù)對象 object
rules 表單驗(yàn)證規(guī)則 object
inline 行內(nèi)表單模式 boolean false
labelPosition 表單域標(biāo)簽的位置 string right/left/top right
labelWidth 表單域標(biāo)簽的寬度,所有的 form-item 都會(huì)繼承 form 組件的 labelWidth 的值 string
labelSuffix 表單域標(biāo)簽的后綴 string

Form Methods

方法名 說明
validate(cb) 對整個(gè)表單進(jìn)行校驗(yàn)的方法
validateField(prop, cb) 對部分表單字段進(jìn)行校驗(yàn)的方法
resetFields 對整個(gè)表單進(jìn)行重置,將所有字段值重置為空并移除校驗(yàn)結(jié)果

Form-Item Attributes

參數(shù) 說明 類型 可選值 默認(rèn)值
prop 表單域 model 字段 string 傳入 Form 組件的 model 中的字段
label 標(biāo)簽文本 string
labelWidth 表單域標(biāo)簽的的寬度,例如 '50px' string
required 是否必填,如不設(shè)置,則會(huì)根據(jù)校驗(yàn)規(guī)則自動(dòng)生成 bolean false
以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號