react响应和处理事件

React 使用最多的,是设计应用的设计UI,而用户界面一个最重要的目的是以有效的方式响应用户输入。用户输入多种多样,有鼠标点击,有键盘按键,有窗口大小的更改,如果运行在手机上的话,还得响应拖拽等手势操作。

应对这些复杂的情形的办法是抽象,把用户的任何操作都当做一种事件,如果你了解原来的web开发的话,那么你一定知道,很多开发的精力都要放在响应DOM事件的处理之上。

做一个简单的程序(把页面显示给用户),有一个按钮,上面是一个数字,点击一次按钮,数字就增加1.麻雀虽小五腑俱全,这个应用实例看起来简单,但很实用,每次你点击按钮时,一个点击事件就会产生,在代码中监听这个事件,然后依赖 React提供给我们的各种机制,响应该事件,然后让显示的数值加一

例:

var Counter = React.createClass({
    render: function() {
         var textStyle= {
             fontSize:72,
             fontFamily:"sans-serif",
             color: "#333",
             fontWeight:"bold"
         };
         return (
             <div style={textStyle}>
                {this.props.display}
             </div>
        );
    }
});
var CounterParent = React.createClass({
     getInitialState:function() {
             return {
                 count: 0
             };
         },
         render: function() {
             var backgroundStyle ={
                 padding:50,
                 backgroundColor:"#FFC53A",
                 width: 250,
                 height:100,
                 borderRadius:10,
                 textAlign: "center"
             };
             var buttonStyle ={
                 fontSize:"1em",
                 width:30,
                 height:30,
                 fontFamily:"sans-serif",
                 color: "#333",
                 fontWeight:"bold",
                 lineHeight: "3px"
             };
             return (
                 <div style={backgroundStyle}>
                    <Counter display={this.state.count}/>
                        <button style={buttonStyle}>+</button>
                 </div>
            );
    }
});
ReactDOM.render(
     <div>
        <CounterParent/>
     </div>,
     destination
);

创建了两个组件,Counter用来显示计数信息,CounterParent是Counter组件的父组件,它负责绘制黄色背景以及加号按钮,同时时,在显示计数组件时,传入要显示的数值信息,该数值信息存储在组件的state对象中

当前点击加号按钮时,组件没有任何响应,接下来实现按钮点击后的响应功能,需要做的是响应按钮的点击事件,一旦事件发生

后,增加this.state.count的值,把增加后的值传递给Counter组件。

JSX代码片段中,明确的添加要监听的事件,并设置事件的响应处理函数,在CounterParent组件的实现代码中,添加以下代

码:

increase:function(e) {
     this.setState({
         count: this.state.count+1
     });
 },

render: function() {
...
return  (
         <div style={backgroundStyle}>
            <Counter display={this.state.count}/>
            <button onClick={this.increase} style={buttonStyle}>+
            </button>
         </div>
         );
...
}

添加上面代码后,点击加号按钮,数字就能根据点击的次数做相应的更改了。

事件属性

在increase函数的实现中,它传入了一个变量e,这个变量就是事件对象,该对象包含有很多属性变量,不同事件,里面包含的内 容还不一样,例如,如果事件是鼠标点击后发生的,那么e的对象类型就是MouseEvent, 这个对象里就能够包含很多与鼠标相关 的信息,例如鼠标按下时,被点击的是左键还是右键,如果事件是由键盘发出的,那么事件的类型就是KeyboardEvent, 该对象包含的属性能显示很多键盘相关的信息,例如我们能得知,键盘上那一按钮被按下了。

然而,上面谈到的事件对象是DOM产生的,这些事件对象在进入React框架后,会被React进行二次处理,React 会把他们封装成 一个事件对象叫SyntheticEvent, 它包含以下属性: (把这部分先拷贝到编辑器) 属性 类型

bubbles boolean cancelable boolean currentTarget DOMEventTarget defaultPrevented boolean eventPhase boolean isTrusted boolean nativeEvent DOMEvent preventDefault() void isDefaultPrevented() boolean isPropagationStopped void target DOMEventTarget timeStamp umber type string

以上属性是事件对象的固定部分,对不同的事件,SyntheticEvent对象还会封装不同属性,例如对应MouseEvent 对象,那么 还得封装下列属性:

boolean altKey number button number buttons number clientX number clientY boolean ctrlKey boolean getModifierState(key) number pageX number pageY number screenX number screenY boolean shiftKey

如果DOM发出的是KeyboardEvent对象,那么SyntheticEvent将会 封装下列属性: boolean altKey number charCode boolean ctrlKey boolean getModifierState(key) string key number keyCode string locale number location boolean metaKey boolean repeat boolean shiftKey number which

接下来看看如何利用SytheticEvent对象里面的相关属性, 例如,如果想知道一个按键按下时,是不是shfit键也按下 了,那么只要查询shiftKey 这个属性是不是true就可以了 。于是在事件响应函数中,根据传进来的对象,读取它的 shiftKey 属性,如果该属性是true, 那么表明shift键被按下, 于是在增加计数时,一下子增加10:

increase:function(e) {
     var currentCount = this.state.count;
     if (e.shiftKey){
         currentCount += 10;
     } else {
        currentCount +=  1;
     }
     this.setState({
         count: currentCount
     });
}

添加上面代码后,如果你在用鼠标点击按钮时,按下键盘的shift键,那么计数会一下子增加10,如果没有按,那么计数只会每次添加1

事件处理的注意事项
现在看到的知识React事件处理机制的表面,有很多深层次的要点,还没有了解。真正的web应用,要处理的很多事件比我们当前例子要复杂很多,必须掌握更多React的事件处理技巧,以便满足开发需要。
接下来看看在实际开发中有可能要遇到的各种问题,以及相应的处理办法。
首先要知道,React组件不能直接监听事件

在例子中,监听按钮点击事件的办法是在button控件中添加要监听的事件名字,并提供事件的响应函数,但如果面对的并非html标准控件,而是我们自己定义的React组件,那么,我们不能使臫当前方式去监听和响应事件

例如我们定义了一个控件叫PlusButton, 那么下面这么做是错误的:

var PlusButton = React.createClass({
    render: function() {
        return  (
            <button>+</button
        );
    }
});
<PlusButton onClick={this.increase}/>
从表面上看,这句代码逻辑上没什么问题,但是组件对html标准控件的封装和延伸,对标准控件进行事件监听的方式,不能直接应用到组件上。因为React 无法区别这种做法到底是监听事件还是给组件属性赋值。

但这不是说,如果标准控件被React组件封装后就不能从组件外层实现事件监控了,需要绕个弯去解决这个问题,例如,我们可以把事件的响应函数当做属性从外面传给组件,例如看以下代码:

var PlusButton = React.createClass({
    render: function() {
        return (
             <button onClick={this.props.clickHandler} style={this.props.showStyle}>
                            +
             </button>
             );
    }
});                 
var CounterParent = React.createClass({
    ....
    render: function() {
        var  backgroundStyle ={
             padding:50,
             backgroundColor:"#FFC53A",
             width: 250,
             height:100,
             borderRadius:10,
             textAlign: "center"
        };
        var buttonStyle = {
             fontSize:"1em",
             width:30,
             height: 30,
             fontFamily: "sans-serif",
             color: "#333",
             fontWeight:"bold",
             lineHeight:"3px"
        };
        return  (
            <div style={backgroundStyle}>
                <Counter display={this.state.count}/>
                <PlusButton clickHandler={this.increase} 
                showStyle={buttonStyle}/>
            </div>
        );
    }
    ....
}

上面代码修改后,点击按钮,计数功能仍然正常运行。html标准控件定义在PlusButton组件内部,先在button控件上监听onClick事件,而事件的响应函数则从控件外部当做属性传递进去

this 关键字在事件处理函数中的指向

必须要注意,在事件响应函数中,如果你用到关键字this的话,这个this指代的是定义响应函数的组件对象,例如在CountParent中,如果我们在increase函数中把this打印出来:

increase: function(e) {
    console.log("CounterParent: "   +   this);
    var currentCount = this.state.count;
    if (e.shiftKey){
        currentCount +=  10;
    } else {
        currentCount+=  1;
    }
    this.setState({
        count:currentCount
    });
},
添加上面代码,运行后,在浏览器的控制台观察输出信息,可以发现,打印出的this对象内容描述的是组件CounterParent.

React框架会把this绑定到执行函数所属的组件对象,但是这种自动绑定只有在组件是通过createClass API创建时才行。

React的事件响应机制如此设计是出自于一些考量的: 首先考虑的是浏览器的兼容性,其次要考虑的是事件处理的效率。

React 把所有事件对象封装到SyntheticEvent这个对象里,是为了兼容旧版本的浏览器。封装了后,在React开发过程中,就不必要考虑浏览器的不同版本,然后编写不同逻辑的代码,因此React大大简化了事件处理的开发逻辑。其次,当设计的用户界面越复杂,需要响应的事件越多,那么手动实现各种事件响应的代码逻辑就会越来越复杂,为了应对这种情况,React并不是机械的去处理各个不同的事件,在低下它事件上使用的是 一个总的事件响应函数来捕捉DOM产生的所有事件,先做相应处理,然后再分发给对应的响应函数,通过这种方式,React能够优化事件的分发流程,进而提高事件的响应效率

结论: 本节,深入了解了React的事件处理机制,先掌握了基本的事件监听和响应放法,然后,又研究了在一些特殊情况下,如何实现事件响应,通过本节,对React的事件处理机制应该会有较为深刻的认识。





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值