react入门(2)
接着上一次的讲,如果没有看过上一篇文章的小伙伴可以先看一下http://www.cnblogs.com/sakurayeah/p/5807821.html
五、React事件
可以先看一下官网讲解的内容
案例6:以点击事件为例
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> </head> <body> <div id="example"></div> <script type="text/babel"> var fn3 = function(){/*方法3*/ console.log(333) } var Test = React.createClass({ fn1:function(){/*方法1*/ console.log(111) },/*注意这里是逗号哦*/ render:function(){ var fn2 = function(){/*方法2*/ console.log(222) }; return ( <div> <button onClick={this.fn1}>方法1</button> <button onClick={fn2}>方法2</button> <button onClick={fn3}>方法3</button> <button onClick={this.fns.fn4}>方法4</button> </div> ) } }); Test.prototype.fns = {/*方法4,原型链*/ fn4:function(){ console.log(444) }, } ReactDOM.render( <Test />, document.getElementById('example') ) </script> </body> </html>
上面列举了四种方法,效果图如下
react本身定义了一套事件机制遵守W3C标准,规范规定事件名称前面小写,后面关键字首字母大写。
例如(箭头前为js写法,箭头后为react的写法)
onclick --> onClick。
onchange --> onChange
onfocus --> onFocus
onblur --> onBlur
onmousemove --> onMouseMove
...... (有很多,可以参考官网看一下)
六、this.props.children
this.props 对象的属性与组件的属性一一对应,但是有一个例外,就是 this.props.children 属性。它表示组件的所有子节点。
案例7:
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Test = React.createClass({ render:function(){ return ( <div> {this.props.children} </div> ) } }); var Box = React.createClass({ render:function(){ return( <Test> <span>序号1,</span> <span>序号2,</span> <span>序号3,</span> </Test> ) } }); ReactDOM.render( <Box />, document.getElementById('example') ) </script> </body> </html>
效果如下
上图所示,红框勾起来的部分,div里面包含的所有标签都是 Test 这个组件里面的。
如果把Test这个组件删除掉,如下图所示,如果你将下面红框框起来的代码删除
就会发现报错,如下图所示
分析如下
Box组件里<Test>标签里的内容,通过this.props.children,相当于放到了Test组件里去了,然后再将Test组件放在Box组件里,最后将Box组件渲染在页面上,也就相当于如下
var Test = React.createClass({ render:function(){ return ( <div> <span>序号1,</span> <span>序号2,</span> <span>序号3,</span> </div> ) } }); var Box = React.createClass({ render:function(){ return( <Test /> ) } }); ReactDOM.render( <Box />, document.getElementById('example') )
效果如下
案例8:
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Test = React.createClass({ render:function(){ return ( <div> { React.Children.map(this.props.children, function(child,index) { return <p>序号{index}:{child}</p>; }) } </div> ) } }); var Box = React.createClass({ render:function(){ return( <Test> <span>电影</span> <span>电视剧</span> <span>综艺</span> </Test> ) } }); ReactDOM.render( <Box />, document.getElementById('example') ) </script> </body> </html>
效果如下
先来说一下上面这个例子中涉及到的map循环
React 提供一个工具方法 React.Children 来处理 this.props.children 。我们可以用 React.Children.map 来遍历子节点,而不用担心 this.props.children 的数据类型是 undefined 或者是 object 还是 array。
把map循环:和for循环对比一下来解释
先写一个for循环
var arr = [1,2,3,4]; for(var i=0;i<arr.length;i++){ console.log(arr[i]) }
这里有一个点要注意一下,Test组件里面的子节点的个数(上面的例子中Text组件的有三个span子节点)会影响this.props.children的值:
- 如果Test组件没有子节点,this.props.children为undefined
- 如果Test组件有一个子节点,this.props.children为object
- 如果Test组件有多个子节点,this.props.children为array
上面一个例子也就相当于,将Box组件里Test标签里的三个子节点,通过this.props.children放到了Test组件里去,这时候也就相当于Test组件里有一个数组了,数组里面是对应的三个span节点,通过map遍历,将span标签放入到p标签中去,然后再将Test组件放到Box组件里,最终将Box组件渲染到页面上。如下所示
<body> <div id="example"></div> <script type="text/babel"> var Test = React.createClass({ render:function(){ var arr = [<span>电影</span>, <span>电视剧</span>, <span>综艺</span>]; var temp = []; for(var i=0;i<arr.length;i++){ temp.push(<p>序号{i}:{arr[i]}</p>); } return ( <div> {temp} </div> ) } }); var Box = React.createClass({ render:function(){ return( <Test /> ) } }); ReactDOM.render( <Box />, document.getElementById('example') ) </script> </body>
效果如下
除了React.Children.map,关于React.Children的更多的方法,可以看官网
七、传递props
React 里有一个非常常用的模式就是对组件做一层抽象。组件对外公开一个简单的属性(Props)来实现功能,但内部细节可能有非常复杂的实现。
案例9:父-子组件的通信
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Parent = React.createClass({ clicks:function(){ alert('您好') }, render:function(){ return ( <div> <Child user="tom" age="11" fn={this.clicks} /> <Child user="sam" age="13" fn={this.clicks} /> </div> ) } }); var Child = React.createClass({ render:function(){ return ( <div> 年纪:{this.props.user},年龄: {this.props.age}, <button onClick={this.props.fn}>点击</button><br /> </div> ) } }); ReactDOM.render( <Parent />, document.getElementById('example') ) </script> </body> </html>
效果如下
分析如下
这样其实也就是相当于实现了组件之间的通信
案例10:
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Parent = React.createClass({ clicks:function(){ alert('您好') }, render:function(){ return ( <div> <Child user="tom" age="11" fn={this.clicks} /> </div> ) } }); var Child = React.createClass({ render:function(){ var { user, age, fn } = this.props; return ( <div> 年纪:{user},年龄: {age}, <button onClick={fn}>点击</button><br /> </div> ) } }); ReactDOM.render( <Parent />, document.getElementById('example') ) </script> </body> </html>
效果如下
这个例子和上面一个例子相同,只是在子组件Child里面的写法有一点不同(如下图红色框框勾出来的),这里我就不讲解,大家看一下知道还可以这么写就行了
八、关于{...other}
有时把所有属性都传下去是不安全或啰嗦的。这时可以使用解构赋值中的剩余属性特性来把未知属性批量提取出来。
列出所有要当前使用的属性,后面跟着 ...other
。
案例11:
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Parent = React.createClass({ clicks:function(){ alert('click') }, enters:function(){ console.log('enter') }, render:function(){ return ( <div> <Child user="tom" age="11" onClick={this.clicks} onMouseEnter={this.enters} /> </div> ) } }); var Child = React.createClass({ render:function(){ var { user, age, ...other } = this.props; return ( <div> 年纪:{user},年龄: {age}, <button {...other}>移动</button><br /> </div> ) } }); ReactDOM.render( <Parent />, document.getElementById('example') ) </script> </body> </html>
效果如下(当鼠标移到按钮上的时候,打印enter,当点击按钮的时候,弹框显示click)
分析如下
我们现在要传递的有user、age、onClick、onMouseEnter(如下图所示)
当前我们列出来的属性有user、age(如下图所示),剩下两个onClick和onMouseEnter通过 ...other 来传递,这样写起来也比较简洁
使用 ...other 能确保把所有 props 传下去,除了那些已经被使用了的。
九、关于{...this.props}
案例12:
其实也就是 案例11 的另一种写法(大家知道这么写就行了,我就不详细解释了)
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Parent = React.createClass({ clicks:function(){ alert('click') }, enters:function(){ console.log('enter') }, render:function(){ return ( <div> <Child user="tom" age="11" onClick={this.clicks} onMouseEnter={this.enters} /> </div> ) } }); var Child = React.createClass({ render:function(){ return ( <div> 年纪:{this.props.user},年龄: {this.props.age}, <button {...this.props}>移动</button><br /> </div> ) } }); ReactDOM.render( <Parent />, document.getElementById('example') ) </script> </body> </html>
效果如下
案例13:
<!DOCTYPE html> <html> <head> <title>react入门</title> <meta charset="utf-8"> <script src="https://npmcdn.com/react@15.3.1/dist/react.min.js"></script> <script src="https://npmcdn.com/react-dom@15.3.1/dist/react-dom.min.js"></script> <script src="https://npmcdn.com/babel-core@5.8.38/browser.min.js"></script> <style type="text/css"> .tab{background:yellow;} </style> </head> <body> <div id="example"></div> <script type="text/babel"> var Parent = React.createClass({ render:function(){ return ( <div> <Child checked={true} /> <Child checked={false} /> </div> ) } }); var Child = React.createClass({ render:function(){ var bgOne = { border:'1px solid red' }; var bgTwo = { border:'1px solid blue' }; var { checked } = this.props; var res = checked?'选中':'不选中'; var bg = checked?bgOne:bgTwo; return ( <div style={bg}> <input type="checkbox" checked={checked} /> {res} </div> ) } }); ReactDOM.render( <Parent />, document.getElementById('example') ) </script> </body> </html>
效果如下
父组件中传递的信息只有checked是true或者false
在子组件里,我们可以通过这个值来完成多个效果(input是否选中、文字、边框颜色)
在上面的例子中还有一个问题,父组件中我们传递的信息是checked={true},子组件里面input上的属性checked={checked}。这里希望大家不要混淆了,如下图所示
checked={checked}还可以写成checked={this.props.checked}
另外值得一提的是 案例13 里面,我们不可以改变复选框的状态,这里就涉及到了受阻组件和不受阻组件,这里贴一个教程。