玩转Reactjs第五篇-基础知识(事件&条件&列表&表单)

一、前言

其实在前面介绍组件的时候,已经用到了这些知识,本章节我们重点分析下,并与Vue的用法比较。

二、事件

    Reactjs中事件处理方式与原生态DOM的非常类似,只不过使用JSX的语法,采用的是小驼峰的表达方式,比如onClick,onChange,我们以SearchHot.js的"下一批"功能为例,当点击按钮,更新热词。

return (
        <div className="d"> 
            <div className="s">大家都在搜:<a href="#" onClick={this.changeHot} style={{marginLeft:100}}>下一批</a></div>
            <ul className="su">
                {/*引用变量表达式  */}
                 {hotList}
            </ul>

        </div> 
        )

在a标签上增加onClick响应事件,调用的方法为changeHot,下面我们对该方法定义

changeHot(){
        this.setState({hotItem:['电视','手机','电脑','平板']})
    }

在此方法中,我们调用setState更新hotItem属性。如果直接运行,将会报this为undefined的错误,我们还需要在组件初始化方法中,将该方法绑定到组件对象。

constructor(props){
        // 1、调用父类构造方法
        super(props);
        //2、初始化state对象
        this.state = {hotItem:['口罩','手套','酒精',]};
        //绑定this
        this.changeHot = this.changeHot.bind(this);
    }

除了这种bind方式,还可以将changeHot改造为箭头函数,在箭头函数中,this指向的函数的本身,而不是函数的调用者,可以参考ES6系列教程第八篇--箭头函数详解

changeHot = () =>this.setState({hotItem:['电视','手机','电脑','平板']});

我们在a标签上增加一个默认事件,href="search.json"

return (
        <div className="d"> 
            <div className="s">大家都在搜:<a href="search.json" onClick={this.changeHot} style={{marginLeft:100}}>下一批</a></div>
            <ul className="su">
                {/*引用变量表达式  */}
                 {hotList}
            </ul>

        </div> 
        )

此时再次点击按钮,发现页面跳转到search.json,这是因为执行了默认事件。现在我们需要阻止默认事件或者冒泡。

changeHot(e){
        e.preventDefault();
        e.stopPropagation();
        this.setState({hotItem:['电视','手机','电脑','平板'] })
    }

再次点击时,功能正常。

事件方法中会隐形传入一个event参数,通过调用该参数的preventDefault(),stopPropagation()阻止默认事件以及冒泡。

传参是事件的基本的功能,我们看下React如何实现传参。

return (
        <div className="d"> 
            <div className="s">大家都在搜:<a href="search.json" onClick={this.changeHot.bind(this,1,"ok")} style={{marginLeft:100}}>下一批</a></div>
            <ul className="su">
                {/*引用变量表达式  */}
                 {hotList}
            </ul>

        </div> 
        )

在调用的时候绑定this对象,并依次传递相关的参数(注意:事件方法已经绑定了this,可以不需要再在初始化方法中重复绑定),在changeHot中接受并处理参数。

changeHot(id,name,e){
        e.preventDefault();
        e.stopPropagation();
        this.setState({hotItem:['电视','手机','电脑','平板'] });
        console.log("id:"+id);
        console.log("name:"+name)
    }

无论传递多少参数,隐形的event参数始终处于最后的位置。

在Vue中,事件的处理使用的是v-on内置的指令,并通过事件的修饰符简化了诸如阻止默认事件,冒泡等写法。而JSX语法中没有指令的概念,其处理方式更接近原生的DOM。

三、条件

在前面章节中,我们介绍JSX仅支持三目以及&&符运算的嵌入,而不支持if...else条件语句。我们先看三目运算和&&。

在SearchBox.js中,我们用this.state.isSearch标志符控制button按钮的disabled属性,当this.state.isSearchShow为true,按钮有效,false则无效。

        return(
            <div style={{width:300,margin:10}}>
                <input type="text" style={{width:150}} onChange={this.handleChange}></input>&nbsp;&nbsp;
               <button onClick={this.onSearchClick} disabled={this.state.isSearchShow?"":"disabled"}>搜索</button>
            </div>
        )

也可以改写&&运算

return(
            <div style={{width:300,margin:10}}>
                <input type="text" style={{width:150}} onChange={this.handleChange}></input>&nbsp;&nbsp;
               <button onClick={this.onSearchClick} disabled={!this.state.isSearchShow&&"disabled"}>搜索</button>
            </div>
        )

在js中,true && expression 总是会返回 expression, 而 false && expression 总是会返回 false。

如果是多个条件组合,三目运算就无法满足了,比如不同的状态,显示button的不同背景色,此时就需要用到if...else。

render(){
        //定义color变量,并根据状态显示不同的颜色
        let color;
        if(this.state.color<10){
            color="green"
        }else if(this.state.color<20){
            color="blue"
        }else if(this.state.color<30){
            color="red"
        }else{
            color="orange"
        }

        return(
            <div style={{width:300,margin:10}}>
                <input type="text" style={{width:150}} onChange={this.handleChange}></input>&nbsp;&nbsp;
               <button onClick={this.onSearchClick} disabled={!this.state.isSearchShow&&"disabled"} style={{backgroundColor:color}}>搜索</button>
            </div>
        )
    }

虽然JSX中无法直接使用if...else,但可以通过在代码段中,定义color的变量并条件赋值,再在JSX中插入color变量表达式。

在Vue中使用v-if,v-else指令进行条件控制,并对控件的隐藏和显示提供了v-show,使用更方便。

四、列表

Reactjs中对于列表使用map方法进行遍历,并拼装成JSX表达式。以SearchList.js的搜索结果列表展示为例:

render(){
      //1、从props中获取searchListVal,封装列表
      const searchValList = this.state.searchListVal.map((value)=>
        (<li>
          {value}
        </li>)
      );

      return(
        <div className="d">
            <div className="s">搜索结果:</div>
            {/* 引入插槽代码 */}
            {this.props.children}
            <ul className="u" ref={this.searchul}>
              {/* 引用对象表达式*/}
               {searchValList}
            </ul>
        </div>       
      )
    }

遍历searchListVal数组,拼装li表达式。此时我们打开控制台,会发现有如下的warning

这个告警的意思,list应增加一个key属性。

 const searchValList = this.state.searchListVal.map((value)=>
        (<li key={value.toString()}>
          {value}
        </li>)
      );

告警消失,那加上这个key有什么作用呢?

这要从diff算法的原理说起。diff运算时,对于同一节点下的子元素,进行遍历比较,如果不一致,则产出一个mutation。如下:

//老节点
<ul>
  <li>first</li>
  <li>second</li>
</ul>
//新节点
<ul>
  <li>first</li>
  <li>second</li>
  <li>third</li>
</ul>

该样例中,ul的子元素li,新老节点中第一个和第二个是完全一样的,所以无需变动,仅在尾部插入第三个li元素,就可以完成节点的更新,效率很高。如果是头部插入一个li呢?

/老节点
<ul> 
  <li>first</li>
  <li>second</li>
</ul>
//新节点
<ul>
   <li>third</li>
  <li>first</li>
  <li>second</li>
</ul>

在diff运算过程中,比较发现第一个,第二个li元素不一样(老节点的第一个为first,新节点的第一个为third),将会销毁重建,效率会非常低。效率最高的的更新操作,仅在头部插入一个third,其他节点保持不变。为了解决这个问题,引入了key。

/老节点
<ul> 
  <li key="1">first</li>
  <li key="2">second</li>
</ul>
//新节点
<ul>
  <li key="3">third</li>
  <li key="1">first</li>
  <li key="2">second</li>
</ul>

diff运算过程中,不是直接遍历比较,而是优先查找是否有相同的key,新老节点都有key为1,2的li元素,且值没有变化,这两个节点将保持不变,最终仅在头部插入key为3的li元素,实现了高效率的更新。

所以,key需要有以下两个特点:

  • key一定是在同级的兄弟节点间设置,因为非同级节点不会进行diff运算。
  • key的值在兄弟节点间必须唯一,一般用id等,最好不要用列表索引(索引可能会变化)

在Vue用使用v-for进行列表渲染,其中也需要设置key,原理是一致的。

五、表单

表单标签包括select,input,textarea,checkbox,radio等,他们是最能说明双向绑定的过程,比如SearchBox.js中的搜索输入框input

handleChange(e){
       this.setState({searchVal:e.target.value});
    }
....
return(
            <div style={{width:300,margin:10}}>
                <input type="text" style={{width:150}} onChange={this.handleChange} value={this.state.searchVal}></input>&nbsp;&nbsp;
               <button onClick={this.onSearchClick} >搜索</button>
            </div>
        )

input框的每次输入,通过onChange捕捉变化事件,并响应handleChange方法,将input的当前值更新到state中的searchVal(这就是view->model过程);searchVal赋值给input的value,searchVal值的变化,又反馈到input的value(这就是model->view)。有同学会问,这这么做不是多此一举么,其实不然,在实际使用过程中,我们会在handleChange中对输入值e.target.value进行处理,比如说银行卡号,4个数字一组,做分割处理,再设置给input框输出展示。

Reactjs还提供一种操作DOM获取input的输入值的方式,即使用ref。

首先在构造函数中定义ref

 constructor(props){
       super(props);
       this.state = {searchVal:"",isSearchShow:true,color:25};
       this.onSearchClick = this.onSearchClick.bind(this);
       this.handleChange = this.handleChange.bind(this); 
       //定义ref
       this.input = React.createRef();
    }

然后设置input的ref属性

 return(
            <div style={{width:300,margin:10}}>
                <input type="text" style={{width:150}} onChange={this.handleChange} ref={this.input} value={this.state.searchVal}></input>&nbsp;&nbsp;
               <button onClick={this.onSearchClick} >搜索</button>
            </div>
        )

就可以使用ref获取input的对象句柄,比如handleChange通过ref的方式获取input的值

handleChange(e){
    this.setState({searchVal:this.input.current.value});
    }

使用的时候别忘了current关键字。此时input可以通过ref进行DOM操作,称为非受控组件。虽然这种模式打破了数据驱动view的原则,但是有时候还是比较方便的,比如获取滚动条的高度。

在Vue中可有类似的做法,通过自定义的指令操控DOM节点。

六、总结

本章节介绍了Reactjs的事件,条件,列表,表单的基本用法,并与vue进行了简单的比较。

事件的隐形event参数的使用,阻止默认事件以及冒泡,传递参数。

条件的三目运算,&&符,以及if...else条件的使用

列表使用map遍历,以及key的原理。

表单的两种不同的获取对象值的方法。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值