React中的表单

1.表单

在 React 里,HTML 表单元素的工作方式和其他的 DOM 元素有些不同,这是因为表单元素通常会保持一些内部的 state。例如这个纯 HTML 表单只接受一个名称:

<form>
	<label>
    	名字:
    	<input type="text" name="name" />
  	</label>
  	<input type="submit" value="提交" />
</form>

此表单具有默认的 HTML 表单行为,即在用户提交表单后浏览到新页面。如果你在 React 中执行相同的代码,它依然有效。但大多数情况下,使用 JavaScript 函数可以很方便的处理表单的提交, 同时还可以访问用户填写的表单数据。实现这种效果的标准方式是使用“受控组件”。

2.受控组件

在 HTML 中,表单元素(如<input><textarea><select>)之类的表单元素通常自己维护 state,并根据用户输入进行更新。而在 React 中,可变状态(mutable state)通常保存在组件的 state 属性中,并且只能通过使用 setState() 来更新。
 
我们可以把两者结合起来,使 React 的 state 成为“唯一数据源”。渲染表单的 React 组件还控制着用户输入过程中表单发生的操作。被 React 以这种方式控制取值的表单输入元素就叫做“受控组件”。

class NameForm extends React.Component {
	constructor(props) {
    	super(props);
    	this.state = {value: ''};

    	this.handleChange = this.handleChange.bind(this);
    	this.handleSubmit = this.handleSubmit.bind(this);
  	}

  	handleChange(event) {
    	this.setState({value: event.target.value});
  	}

  	handleSubmit(event) {
    	alert('提交的名字: ' + this.state.value);
    	event.preventDefault();
  	}

  	render() {
    	return (
      	<form onSubmit={this.handleSubmit}>
        	<label>
          	名字:
          	<input type="text" value={this.state.value} onChange={this.handleChange} />
        	</label>
        	<input type="submit" value="提交" />
      	</form>
    	);
  	}
}
3.textarea 标签

在 HTML 中, 元素通过其子元素定义其文本:

<textarea>
  你好, 这是在 text area 里的文本
</textarea>

而在 React 中,<textarea> 使用 value 属性代替。这样,可以使得使用 <textarea> 的表单和使用单行 input 的表单非常类似:

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: '请撰写一篇关于你喜欢的 DOM 元素的文章.'
    };

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('提交的文章: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          文章:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}

请注意,this.state.value 初始化于构造函数中,因此文本区域默认有初值。

4.select 标签

在 HTML 中,<select> 创建下拉列表标签。例如,如下 HTML 创建了水果相关的下拉列表:

<select>
  <option value="grapefruit">葡萄柚</option>
  <option value="lime">酸橙</option>
  <option selected value="coconut">椰子</option>
  <option value="mango">芒果</option>
</select>

请注意,由于 selected 属性的缘故,椰子选项默认被选中。React 并不会使用 selected 属性,而是在根 select 标签上使用 value 属性。这在受控组件中更便捷,因为您只需要在根标签中更新它。

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {value: 'coconut'};

    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({value: event.target.value});
  }

  handleSubmit(event) {
    alert('你喜欢的风味是: ' + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          选择你喜欢的风味:
          <select value={this.state.value} onChange={this.handleChange}>
            <option value="grapefruit">葡萄柚</option>
            <option value="lime">酸橙</option>
            <option value="coconut">椰子</option>
            <option value="mango">芒果</option>
          </select>
        </label>
        <input type="submit" value="提交" />
      </form>
    );
  }
}

总的来说,这使得 <input type="text">, <textarea><select> 之类的标签都非常相似—它们都接受一个 value 属性,你可以使用它来实现受控组件。

5.文件 input 标签

在 HTML 中,<input type=“file”> 允许用户从存储设备中选择一个或多个文件,将其上传到服务器,或通过使用 JavaScript 的 File API 进行控制。因为它的 value 只读,所以它是 React 中的一个非受控组件。

<input type="file" />

input的双向数据绑定

  • 将数据模型中的数据展示在表单控件内
  • 当表单控件发生更改的时候,修改数据模型中的数据
6.处理多个输入

当需要处理多个 input 元素时,我们可以给每个元素添加 name 属性,并让处理函数根据event.target.name 的值选择要执行的操作。

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          参与:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          来宾人数:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}
7.受控输入空值

在受控组件上指定 valueprop 可以防止用户更改输入。如果指定了 value,但输入仍可编辑,则可能是意外地将 value 设置为 undefinednull

ReactDOM.render(<input value="hi" />, mountNode);

setTimeout(function() {
  ReactDOM.render(<input value={null} />, mountNode);
}, 1000);
8.综合示例
//多种表单控件的双向数据绑定
import React,{Component} from 'react';
class MyTest extends Component{
    constructor(props) {
        super(props);
        this.state = {
            genders:[{name:'男',value:'man'},{name:'女',value:'woman'}],
            addresses:[{name:'上海',value:'Shanghai'},{name:'北京',value:'Beijin'}],
            hobby:[{name:'游泳',value:'swimming'},{name:'跳舞',value:'dancing'},{ name:'唱歌',value:'singing'}],
            form:{username:'',password:'',age:'',gender:'',hobbies:[],address:'',eva:''},
            msg:'个人简历'
        };
    }
    //事件处理程序
    inputChange = (attr,e)=>{
        this.setState({
            form:{...this.state.form,[attr]:e.target.value}
        });
    }
    checkboxChange = (e)=>{
        //如果数组中没有它的值就添加,如果有就删除
        let value = e.target.value;
        let hobbies = [...this.state.form.hobbies];
        if(hobbies.includes(value)){
            //移除 找到当前元素索引然后通过索引移除
            hobbies.filter((item)=>{
                return item !=  value;
            });
        }else{
            //添加
            hobbies = hobbies.concat(value);
        }
        this.setState({
            form:{...this.state.form,hobbies:hobbies}
        },()=>{
            console.log(this.state.form.hobbies);
        })
    }
    btnSubmit = ()=>{
        let obj = {...this.state.form};
        console.log(obj);
    }
    
    render(){
        const {form} = this.state;
        return (
            <div style={{padding:20}}>
                <h1>{this.state.msg}</h1>
                <form>
                    用户名:
                    <input value={form.username} type='text' onChange={this.inputChange.bind(this,'username')}/>
                    <br />
                    密码:
                    <input value={form.password} type='password' onChange={this.inputChange.bind(this,'password')}/>
                    <br />
                    年龄:
                    <input value={form.age} type='text' onChange={this.inputChange.bind(this,'age')}/>
                    <br />
                    性别:
                    {
                        this.state.genders.map((item,index)=>{
                            return (
                                <label key={index}>
                                    <input type='radio' value={item.value} checked={form.gender===item.value?true:false} onChange={this.inputChange.bind(this,'gender')}/>{item.name}
                                </label>
                            );
                        })
                    }
                    <br />
                    爱好:
                    {
                        this.state.hobby.map((item, index) =>{
                            return (
                                <label htmlFor={item.value} key={index}>
                                    <input id={item.value} type='checkbox' value={item.value} checked={form.hobbies.includes(item.value)} onChange={this.checkboxChange}/>{item.name}
                                </label>
                            );
                        })
                    }
                    <br />
                    地址:
                    <select value={form.address} onChange={this.inputChange.bind(this,'address')}>
                        <option value=''>请选择</option>
                        {
                            this.state.addresses.map((item,index)=>{
                                return <option key={index} value={item.valeu}>{item.name}</option>
                            })
                        }
                    </select>
                    <br />
                    自我评价:
                    <br />
                    <textarea value={form.eva} cols="30" rows="10" onChange={this.inputChange.bind(this,'eva')}></textarea>
                    <br />
                </form>
                <button onClick={this.btnSubmit} style={{width:100}}>提交</button>
            </div>
        );
    }
}
export default MyTest;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值