React继续--组件开发
属性 : props
组件应该提供一些属性供开发者在不同的场景下可以对组件实例元素的行为 外观进行调整,这样可以提高组件的利用效率。
React.render( < EzLampComp onoff="off" /> , document.querySelector("#content"));
将一个JavaScript表达式赋给React元素的属性
var myOnoff = "on"; React.render( < EzLampComp onoff={myOnoff} />, document.querySelector("#content"));
让小灯1秒亮1秒暗的闪烁
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ex15:EzLampComp</title> <script src="lib/react.js"></script> <script src="lib/JSXTransformer.js"></script> <!--组件样式--> <style> .ez-lamp{ display : inline-block; margin : 5px; width : 30px; height : 30px; border-radius : 50%; } .ez-lamp.on{ opacity : 1; background : -webkit-radial-gradient(30% 30%,white 5%,red 95%); } .ez-lamp.off{ opacity : 0.5; background : -webkit-radial-gradient(30% 30%,#888 5%,red 95%); } </style> </head> <body> <div id="content"></div> <script type = "text/jsx"> //定义React组件 var EzLampComp = React.createClass({ render : function(){ //取得属性值 var onoff = this.props.onoff; //返回React元素 if(onoff == "on") return <span className = "ez-lamp on"></span>; //JSX else return <span className = "ez-lamp off"></span>; //JSX } }); //渲染React元素 var myOnoff = "on"; setInterval(function(){ //获取当前时间,计算已运行时长 if(myOnoff=="on"){ myOnoff="off"; }else{ myOnoff="on"; } React.render( <EzLampComp onoff={myOnoff}/> , //<--JSX document.querySelector("#content")); },1000); </script> </body> </html>
内联样式 ------直接在元素上声明内联样式
在React元素中声明样式,需要给出一个JSON对象,其字段对应样式名称
var myStyle = { width:"200px", height:"200px" }; //JSX var e = <div style={myStyle} />; //JavaScript var e = React.createElement( "div",{ style : myStyle }); //render React.render(e,...);
注:
对应样式名称的字段,需要使用驼峰式命名,如border-radius样式需要使用borderRadius
样式名称中的供应商前缀(-webkit, -moz, -o, -ms),除ms外都需要大写首字母,如-webkit-transition通过WebkitTransition,-ms-transition通过msTransition
eg:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>ex15:EzLampComp</title> <script src="lib/react.js"></script> <script src="lib/JSXTransformer.js"></script> <style> .ez-lamp{ display : inline-block; margin : 5px; width : 30px; height : 30px; } </style> </head> <body> <div id="content"></div> <script type = "text/jsx"> //定义React组件 var EzLampComp = React.createClass({ render : function(){ //取得属性值 var color = this.props.color, onoff = this.props.onoff, mode = this.props.mode; //亮光颜色 var lights = { "off":"#888", "on":"#fff" }; //透明度 var opacity ={ "off":0.5, "on":1.0 }; var shape={ "rect":"0%", "circle":"50%" }; //根据属性设置附加的样式 var style = { borderRadius :shape[mode], //对应样式:border-radius opacity : opacity[this.props.onoff], background : "-webkit-radial-gradient(30% 30%," + lights[onoff] + " 5%," + color +" 95%)" }; //返回React元素 return <span className="ez-lamp" style={style}></span>; //JSX } }); //渲染React元素 React.render( //JSX--> <div> <EzLampComp color="green" onoff="off" mode="rect" /> <EzLampComp color="green" onoff="on" mode="circle" /> <EzLampComp color="red" onoff="off" mode="rect" /> <EzLampComp color="red" onoff="on" mode="circle" /> <EzLampComp color="blue" onoff="off" mode="rect" /> <EzLampComp color="blue" onoff="on" mode="circle" /> </div> //<--JSX ,document.querySelector("#content")); </script> </body> </html>
状态记忆 : state
组件实例的外观及行为通过使用props变量进行定制的组件称为无状态/stateless的组件。因为在任何时刻,组件 实例的表现都仅仅取决于外部传入的props属性
让一个组件拥有记忆能力,意味着它不仅能对外界的刺激产生反应,也能根据自身的状态对同样的刺激做出 不同的反应。如开关
- state - 组件的状态变量
每个React组件实例都有一个state变量,用来保存组件的当前状态,使用this.state读取当前状态
- getInitialState() - 设置组件初始状态
getInitialState()方法必须返回一个JSON对象或空值null
- setState(currentState) - 设置组件当前状态
使用this.state来直接设置组件当前状态,但React要求使用setState()方法来进行状态设置。因为,setState()方法会自动 地重新渲染组件
currentState是一个JSON对象,不必包含状态变量的所有字段,setState()方法会 将这个参数值与当前状态this.sate进行合并
eg:开关的寿命只有5次,切换5次后就坏了,之后的点击不再切换并弹出警告框提示用户
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>EzSwitchComp</title> <script src="lib/react.min.js"></script> <script src="lib/JSXTransformer.js"></script> </head> <body> <div id="content"></div> <script type="text/jsx"> //组件定义 var EzSwitchComp = React.createClass({ //设置初始状态 getInitialState : function(){ return {on : false,count:1}; }, //处理点击事件,切换状态 onClick : function(){ //读取并重设状态,这将触发重新渲染 this.setState({on : !this.state.on,count: this.state.count+1}); }, render : function(){ //根据状态设置样式 img = this.state.on ? "img/switch-on.png" : img = "img/switch-off.png"; //返回元素 if(this.state.count+1<8){ return <img src = {img} style={{width:"150px"}} onClick={this.onClick}/>; }else{ return alert("坏了!!!"); } } }); //渲染 React.render( <EzSwitchComp/>, document.querySelector("#content")); </script> </body> </html>
生命周期
在组件实例的整个周期中,React将在特定的时间点调用以下方法:
- componentWillMount() - 组件实例即将挂接(初次渲染)时被调用
- componentDidMount() - 组件实例挂接(初次渲染)后被调用
- componentWillReceiveProps(nextProps) - 组件实例即将设置新属性时被调用
- shouldComponentUpdate(nextProps, nextState) - 组件实例即将重新渲染时被调用,这个方法返回true,;false,那么组件实例就不会被重新渲染
- componentWillUpdate(nextProps, nextState) - 组件实例即将重新渲染时被调用
- componentDidUpdate(prevProps, prevState) - 组件实例重新渲染后被调用
- componentWillUnmount() - 组件实例即将从DOM树移除时被调用
eg:使用componentWillUpdate()方法,使时钟在秒为0时显示为红色字体
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>EzDigiClockComp</title> <script src="lib/react.min.js"></script> <script src="lib/JSXTransformer.js"></script> <!--组件样式--> <style> @font-face { font-family:"LED"; src:url("font/LED.eot?") format("eot"), url("font/LED.woff") format("woff"), url("font/LED.ttf") format("truetype"), url("font/LED.svg#LED") format("svg"); font-weight:normal; font-style:normal; } .ez-digi-clock{ font-family : LED; font-size : 40px; background : #70d355; width: 300px; height:60px; line-height : 60px; text-align : right; padding : 10px; letter-spacing : 5px; } </style> </head> <body> <div id="content"></div> <script type="text/jsx"> //获取并格式化当前时间 var _getTime = function(){ var _=['00','01','02','03','04','05','06','07','08','09'], //补零 d = new Date(), h = d.getHours(), m = d.getMinutes(), s = d.getSeconds(); return [_[h]||h,_[m]||m,_[s]||s].join(":"); }; var onoff="on"; //组件定义 var EzDigiClockComp = React.createClass({ //设置状态变量初始值 getInitialState : function(){ return { time : _getTime(), }; }, //初次渲染后React执行此方法 componentDidMount : function(){ //设置定时器 this.timer = setInterval(function(){ this.setState({time:_getTime()}); }.bind(this),1000); }, //即将从DOM树移除时执行此方法 componentWillUnmount : function(){ //删除定时器 clearInterval(this.timer); }, componentWillUpdate:function(){ if(this.state.time.split(":")[2]=="59"){ onoff="off"; }else{ onoff="on"; } }, render : function(){ var lights = { "off":"red", "on":"#000" }; var style = { color:lights[onoff] }; return <div className="ez-digi-clock " style={style}> {this.state.time} </div>; } }); //渲染 React.render( <EzDigiClockComp />, document.querySelector("#content")); </script> </body> </html>
访问DOM
直接访问_React元素对应的DOM对象
- 设置React元素的ref属性
<input type="text" defaultValue="beijing" ref="q" placeholder="请输入城市拼音,如:beijing"/>
this.refs.q指向input组件对象
- 获得DOM对象
React.findDOMNode(component)
参数component,可以通过this.refs对象获得
eg:简单的天气查询组件,在初次渲染后,让输入文本框自动获得焦点
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>EzWeatherComp</title> <script src="lib/jquery.min.js"></script> <script src="lib/react.js"></script> <script src="lib/JSXTransformer.js"></script> <!--组件样式--> <style> .ez-weather{ background : black; color:white; padding:10px; } .ez-search{ display: flex; flex-flow:row nowrap; } .ez-search input{ flex : 1 0 auto; } .ez-search button{ width:100px; margin:0px 10px; } </style> </head> <body> <div id="content"></div> <script type = "text/jsx"> //定义组件 var EzWeatherComp = React.createClass({ //设置初始状态 getInitialState : function(){ return {waiting:false}; }, componentDidMount:function(){ React.findDOMNode(this.refs.q).focus(); }, //点击按钮时执行搜索 search : function(){ //使用FindDOMNOde()方法读取用户输入值 var el = React.findDOMNode(this.refs.q), city = el.value; //设置为等待状态 this.setState({waiting:true,info:null}); //抓取天气数据。不知道这个API能用多久:-( var url = ["http://api.openweathermap.org/data/2.5/weather?q=",city,",China"].join(""); $.ajax({ url:url, dataType : "jsonp",//jsonp方式跨域读取 success:function(data){ //取消等待,设置天气数据 this.setState({waiting:false,info:data}); }.bind(this) //bind()让函数体内的this指向组件实例 }); }, render : function(){ var waitingEl,infoEl; if(this.state.waiting) //是否需要显示等待动画? waitingEl = <img src="img/waiting.gif"/>; if(this.state.info) //是否需要显示天气数据? infoEl = <pre> {JSON.stringify(this.state.info,null,"\t")} </pre>;
return <div className="ez-weather"> <div className="ez-search"> <input type="text" defaultValue="beijing" ref="q" placeholder="请输入城市拼音,如:beijing"/> <button onClick={this.search}>search</button> </div> {waitingEl} {infoEl} </div>; } }); //渲染 React.render( <EzWeatherComp/>, document.querySelector("#content")); </script> </body> </html>
表单输入
- 文本输入框
//JSX <input type = "text" defaultValue = "demo"/>
设置文本输入框元素的初值,使用defaultValue
- 复选按钮
//JSX <input type = "checkbox" defaultChecked/>
设置初始选中状态,使用defaultChecked
- 单选按钮组
设置单选按钮组的初始选中状态,使用 select元素的defaultValue
//JSX <select defaultValue="A"> <option value="A">China</option> <option value="B">India</option> <option value="C">Japan</option> </select>
eg:登陆
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>EzLoginComp</title> <script src="lib/react.min.js"></script> <script src="lib/JSXTransformer.js"></script> </head> <body> <div id="content"></div> <script type="text/jsx"> //组件定义 var EzLoginComp = React.createClass({ auth : function(event){ var sys = React.findDOMNode(this.refs.sys).value, account = React.findDOMNode(this.refs.account).value, pass = React.findDOMNode(this.refs.password).value; alert([sys,account,pass]); }, render : function(){ return <div className = "ez-login"> <div className="row title"> <h1>登录</h1> </div> <div className="row sys"> <label>系统</label> <select defaultValue="人力资源" ref="sys"> <option value="OA">OA</option> <option value="财务">财务</option> <option value="人力资源">人力资源</option> </select> </div> <div className="row account"> <label>用户</label> <input type="text" defaultValue="Jason" ref="account"/> </div> <div className="row pass"> <label>密码</label> <input type="text" ref="password"/> </div> <div className="row remember"> <input type="checkbox" defaultChecked/> <span>记住密码</span> </div> <div className="row button"> <button onClick={this.auth}>登录</button> </div> </div>; } }); //渲染 React.render(<EzLoginComp/>,document.querySelector("#content")); </script> </body> </html>