React(6)React受控组件的使用


前言

在一个实际的项目中,表单是必不可少的DOM元素。项目中出现的表单元素,React要如何获取用户在表单元素中书写或选择的内容呢?本篇文章就为大家讲解React中受控组件的使用方法。
受控组件:Controlled Component,组件的数据受到state组件状态的控制,我们将这类组件称为“受控组件”。受控组件在使用时要实现组件数据和state组件状态的双向绑定。


一、文本类表单元素的受控控使用方法

文本类表单元素包括文本域、密码域、多行文本域三种表单元素。它们使用value属性来绑定表单元素的默认值,同时使用onChange事件编写当文本内容发生变化时所执行的代码。我们将这种用法称为“value-onChange”组合。

例1:在页面中有一个用于输入昵称的表单元素和一个按钮。用户在文本框中输入自己的昵称,单击按钮后获取用户输入的昵称内容,并在控制台中显示。

class App extends React.Component {
  constructor(props){
    super(props);
    this.state={
      nick:""
    }
  }
  render(){
    return (
      <React.Fragment>
        <label htmlFor="nick">昵称</label>
        <input type="text" id="nick" value={this.state.nick} onChange={(event)=>{this.nickChange(event)}} />
        <div><button onClick={()=>this.getNick()}>获取昵称</button></div>
      </React.Fragment>
    )
  }
}

从上述代码中可以看出,文本框利用value属性绑定了state区的nick数据作为文本框的默认值,即空字符串。同时又为文本框绑定了onChange事件。该事件只需要将文本框中用户输入的内容赋值给state区的nick数据即可。文本框中用户输入的内容可以使用onChange事件函数中的event.tarvar.value获取。

文本框的onChange事件代码如下所示。

onChange(event){
  this.setState({
    nick:event.target.value
  })
}

按钮的单击事件代码如下所示。

getNick(){
  console.log(this.state.nick);
}

从例1中可以看出,文本框中的value属性只能为文本框绑定一个初始值,当文本框中的文本内容发生变化时,还需要借助onChange事件来将文本框的值赋给value属性当初绑定的state数据。

例2:在页面中有一个用于输入留言的多行文本域和一个按钮。用户在多行文本框中输入留言文本,单击按钮后获取用户输入的留言内容,并在控制台中显示。同时随着用户输入文本的增多,在页面中显示已经输入了多少个字符,同时限制最多输入20个字符。

效果图如下所示。

在这里插入图片描述

class App extends React.Component {
  constructor(props){
    super(props);
    this.state={
      message:"",
      inputed:0,
      total:20
    }
  }
  render(){
    return (
      <React.Fragment>
        <label htmlFor="message">留言:(已输入{this.state.inputed}/{this.state.total}</label>
        <textarea id="message" value={this.state.message} onChange={(event)=>{this.messageChange(event)}></textarea>
        <div><button onClick={()=>this.submitMessage()}>提交留言</button></div>
      </React.Fragment>
    )
  }
}

多行文本域的处理方式和文本域的处理方式相同,都是采用value-onChange组合来实现的。当用户在多行文本域中输入内容时,将触发onChange事件,该事件代码如下所示。

messageChange(event){
  let message=event.target.value;
  this.setState({
    inputed:message.length
  })
  if(this.state.inputed<this.state.total-1){
    this.setState({
      message
    })
  }
}

按钮的单击事件代码如下所示。

submitMessage(){
  console.log(this.state.message);
}

在state区中,message数据用来接收用户在多行文本域中输入的内容,inputed数据用来记录已经输入的文本个数,total数据用来指定最多能够输入的文本个数。

二、单选框的受控使用方法

单选框在使用时继续延续文本框和多行文本框的使用方式,唯一不同的是单选框采用的是checked-onChange组合来实现受控操作的。

例3:在页面中有一组用于选择性别的单选框和一个按钮。用户选择了某个单选项之后,单击按钮获取用户所选单选项的内容,并在控制台中显示。

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      sex:'男'
    }
  } 
  render(){
    return (
        <React.Fragment>
            <label>性别:</label>
            <input type="radio" value="男" checked={this.state.sex==="男"} onChange={(event)=>this.radioChange(event)} /><input type="radio" value="女" checked={this.state.sex==="女"} onChange={(event)=>this.radioChange(event)} /><div><button onClick={()=>this.getSex()}>所选性别</button></div>
        </React.Fragment>
    )
  }
}

在上述代码中,每一个单选框同样具备了value属性,但是这个value属性已经和文本框的value属性不一样了,这个value属性为单选框被选中后提供了与其他单选框所不同的数据。checked属性取值为逻辑值,因此绑定的是this.state.sex是不是和指定的取值相等,相等则为true,不相等则为false。

单选框的onChange事件代码如下所示。

radioChange(event){
  this.setState({
    sex:event.target.value
  })
}

按钮的单击事件代码如下所示。

getSex(){
  console.log(this.state.sex);
}

代码中通过checked属性中的判断来获取哪一个单选项默认被选中,再借助onChange事件改变state区的sex数据,以实现checked属性和sex数据的双向绑定。

三、复选框的受控使用方法

复选框和单选框一样,也是用checked-onChange组合来对其进行操作,但是复选框可以选中多个复选项,而单选框只能选择一个,因此复选框的checked属性一应该绑定的是一个数组。

例4:在页面中有一组用于选择爱好的复选框和一个按钮。用户选择了某些复选项之后,单击按钮获取用户所选复选项的内容,并在控制台中显示。

效果图如下所示。

在这里插入图片描述

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      favs:["音乐","电影","游戏","跑步","游泳","读书"],
      fav:["电影"]
    }
  } 
  render(){
    return (
      <React.Fragment>
        <label>爱好:</label>
          {
            this.state.favs.map((item,index)=>{
              return (
                <span key={index}>
                  <input type="checkbox" value={item} checked={this.state.fav.includes(item)} onChange={(event)=>this.checkboxChange(event)} /> {item}
                </span>
              )
          })
        }
        <div><button onClick={()=>this.getFav()}>所选爱好</button></div>
      </React.Fragment>
    )
  }
}

在上述代码中,state区定义了两个数据:favs作为数组提供所有备选的爱好内容,fav作为数组用来存储用户选择的爱好内容。

  • 复选框是由state区的favs进行遍历来实现的。
  • 复选框的checked属性取值为逻辑值,绑定的数据是判断favs数组元素item是否在fav数组中,即fav数组中是否包含favs的数组元素item。这里采用的是ES6为数组新增的includes()方法,该方法直接返回参数是否包含在指定的数值中的逻辑值。

复选框的onChange事件代码如下所示。

checkboxChange(event){
  let temp=event.target.value;    //用户选中的那一个复选框的value属性
  let fav=[...this.state.fav];
  let index=fav.findIndex(item=>item===temp);
  if(index!==-1){
    //单击该复选框时,该复选框的value属性取值在fav数组中存在
    fav.splice(index,1);
  }else{
    //单击该复选框时,该复选框的value属性取值在fav数组中不存在
    fav.push(temp);
  }
  this.setState({fav});
}

按钮的单击事件代码如下所示。

getFav(){
  console.log(this.state.fav)
}

该案例涉及到了大量的数组与数组元素之间的操作。虽然同样使用checked-onChange组合来完成,但是两个数组favs和fav之间要进行大量的判断,才能完成最终的效果。

四、菜单的受控使用方法

<select>菜单在表单元素中表示下拉菜单,是一个单选元素,同样使用value-onChange组合来进行处理。

例5:在页面中有一组用于选择专业的下拉菜单和一个按钮。用户选择了某个专业之后,单击按钮获取用户所选专业的内容,并在控制台中显示。

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      specs:["前端开发","PHP开发","Java开发","UI设计","大数据开发","人工智能"],
      spec:"前端开发"
    }
  }
  render(){
    return (
      <React.Fragment>
        <label>专业:</label>
        <select value={this.state.spec} onChange={(event)=>this.specChange(event)}>
          {
            this.state.specs.map((item,index)=>{
              return <option value={item} key={index}>{item}</option>
            })
          }
        </select>
        <div><button onClick={()=>this.getSpec()}>所选专业</button></div>
      </React.Fragment>
    )
  }
}

在上述代码中,state区定义了两个数据:specs作为数组提供所有备选的专业内容,spec用来存储用户选择的专业内容,因为是单选,因此数据类型为字符串。

  • 下拉菜单的菜单项(即<option>标记)是由state区的specs进行遍历来实现的。
  • 由于下拉菜单项具备容器(即<select>标记),因此<select>标记的value属性用来绑定state区的spec数据,作为默认选中项。
  • <option>的value属性而是为下拉菜单项设置被选中后的取值。

下拉菜单的onChange事件代码如下所示。

specChange(event){
  this.setState({
    spec:event.target.value
  })
}

按钮的单击事件代码如下所示。

getSpec(){
  console.log(this.state.spec)
}

仔细分析,下拉菜单的处理方式本质上和文本框是完全相同的。

五、列表的受控使用方法

<select>列表在表单元素中表示列表选择框,是一个可以复选的元素,同样使用value-onChange组合来进行处理。

例6:在页面中有一组用于选择选修课程的下拉列表和一个按钮。用户选择了某些选修课程后,单击按钮获取用户所选的选修课程内容,并在控制台中显示。

效果图如下所示。
在这里插入图片描述

class App extends Component{
  constructor(props){
    super(props);
    this.state={
      courses:["高等数学","线性代数","概率统计","离散数学","复变函数与积分变换","关系代数"],
      course:[]
    }
  }
  render(){
    return (
      <React.Fragment>
        <label>选修:</label>
        <select value={this.state.course} onChange={(event)=>this.courseChange(event)} multiple size={this.state.courses.length}>
          {
            this.state.courses.map((item,index)=>{
              return <option key={index} value={item}> {item} </option>
            })
          }
        </select>
        <div><button onClick={()=>this.getCourse()}>所选选修课</button></div>
      </React.Fragment>
    )
  }
}

在上述代码中,state区定义了两个数据:courses作为数组提供所有备选的选修课程内容,course用来存储用户选择的选修课程内容,因为是多选,因此数据类型为数组。

这里提供两种不同的机制来完成<select>标记的onChange事件。

1、不借助键盘快捷键实现多选。

courseChange(event){
  let value=event.target.value;
  let course=[...this.state.course];
  // 判断value值是否在course数组中出现过
  let index=course.findIndex(item=>item===value);
  if(index>=0){
    course.splice(index,1);
  }else{
    course.push(value);
  }
  this.setState({course});
}

2、借助键盘快捷键实现多选。

courseChange(event){
  let options=event.target.options;
  let temp=[];   //盛放被选中的option项的索引值的数组
  for(let i in options){
    if(options[i].selected){
      temp.push(i);
    }
  }
  let course=temp.map(item=>options[item].value);
  this.setState({course});
}

上述原理形成的代码可以简化为以下ES6代码:

let options=event.target.options;
let course=Object.keys(options).filter(item=>options[item].selected===true).map(item=>options[item].value);
this.setState({course});

总结

本文是React系列教程的第六篇文章,主要为大家讲解了React表单元素的受控组件操作。文本框、密码域、多行文本域、select列表、select菜单都是采用value-onChange组合来实现受控操作的。单选框、复选框是采用checked-onChange组合来实现受控操作的。同时具有复选功能的复选框和列表需要借助数组来接收用户所选的内容,操作起来较为复杂。明天会为大家系统的讲解React中非受控表单元素的使用方法。

第一讲 初识React框架

第二讲 认识JSX语法格式

第三讲 React组件

第四讲 React 父子组件之间的通信

第五讲 React兄弟组件之间的通信

关于作者

小海前端,具有18年Web项目开发和前后台培训经验,在前端领域著有较为系统的培训教材,对Vue.js、微信小程序开发、uniApp、React等全栈开发领域都有较为深的造诣。入住CSDN,希望能够更多的结识Web开发领域的同仁,将Web开发大力的进行普及。同时也愿意与大家进行深入的技术研讨和商业合作。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小海前端

原创不易,量力支持,感谢打赏。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值