React 是一个用于构建用户界面的JavaScript库
$ bower install react babel --save
<script src="../bower_components/react/react.js"></script>
<script src="../bower_components/react/react-dom.js"></script>
<script src="../bower_components/babel/browser.js"></script>
<script type="text/babel" src="index.js"></script>
ReactDOM
属性JSX
语法转为JavaScript
语法
script
中的type
属性为text/babel
,因为React独有的JSX语法,跟JavaScript不兼容
ReactDOM.render
是 React
的最基本方法,用于将标签模板转为HTML语言,并插入指定的DOM节点
+ <div id="app"></div>
+ <script type="text/babel" src="js/1.react.js"/>
ReactDOM.render(
<h1>珠峰培训</h1>,
document.getElementById('app')
);
上面代码将一个h1标题,插入app元素内部
是一种JS和HTML混合的语法,将组件的结构、数据甚至样式都聚合在一起定义组件,会编译成普通的Javascript。
className=类名
,因为class是Javascript关键字var persons = ['刘德华', '范冰冰', '郭跃'];
var style = {color:'red'};
ReactDOM.render(
<div>
{
persons.map(function (person) {
return <div style={style}>Hello, {person}!</div>
})
}
</div>,
document.getElementById('app')
);
我们可以很直观的将一个复杂的页面分割成若干个独立组件,每个组件包含自己的逻辑和样式 再将这些独立组件组合完成一个复杂的页面。 这样既减少了逻辑复杂度,又实现了代码的重用
React允许将代码封装成组件,然后像插入普通HTML标签一样,在网页中插入这个组件
var Message = React.createClass({
render: function() {
return <h1>Hello</h1>;
}
});
ReactDOM.render(
<Message/>,
document.getElementById('app')
);
this.props
中取出getDefaultProps
函数可以用来定会引起组件的默认属性var Person = React.createClass({
//类似于约定了一个接口文档,用于这是验证传递给组件的属性,
propTypes: {
//定义msg的属性类型为字符串,必须传入
name: React.PropTypes.string.isRequired,
gender: React.PropTypes.string.isRequired,
age:React.PropTypes.number.isRequired
},
getDefaultProps:function(){
return {name:'无名氏'}
},
render: function() {
//属性可以通过属性对象this.props中取出
return (<h1> {this.props.name}
{this.props.gender}
{this.props.age}
</h1>);
}
});
var props = {
gender:'男',
age:18
}
ReactDOM.render(
<Person {...props} />,//属性可以在使用组件时传入
document.getElementById('app')
);
this.props
对象的属性与组件实例的属性一一对应,但this.props.children
属性表示组件的所有子节点
React.Children.map
是一个工具方法,用于实现对数组元素的映射
var Person = React.createClass({
render: function() {
return (
<ol>
{
React.Children.map(this.props.children,
function (child) {
return <li>{child}</li>;
})
}
</ol>
);
}
});
ReactDOM.render(
<Person>
<span>大毛</span>
<span>二毛</span>
<span>三毛</span>
</Person>,
document.getElementById('app')
);
getInitialState
用来定义初始状态var Person = React.createClass({
getInitialState: function() {
return {happy: true};
},
getDefaultProps:function(){
return {name:'无名氏'};
},
handleClick: function(event) {
this.setState({happy: !this.state.happy});
},
render: function() {
var heart = this.state.happy ? '开心' : '不开心';
return (
<p >
{this.props.name} {heart} <br/>
<button onClick={this.handleClick}>变心</button>
</p>
);
}
});
ReactDOM.render(
<Person name="林志玲" />,
document.getElementById('app')
);
常用的事件
剪贴板事件 onKeyDown onKeyPress onKeyUp
键盘事件 onFocus onBlur
焦点事件 onChange onInput onSubmit
鼠标事件 onClick onDoubleClick onMouseDown onMouseEnter onMouseLeave
var Input = React.createClass({
getInitialState: function() {//获取初始状态
return {value: '珠峰培训'};
},
handleChange: function(event) { //处理改变事件
this.setState({value: event.target.value});
},
render: function () {
var value = this.state.value;
return (
<div>
<input style={{color:'red'}} type="text"
value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
);
}
});
ReactDOM.render(<Input/>, document.getElementById('app'));
注意: 如果给表单元素设置了
value
属性,则必须指定onChange
事件处理函数,否则 此字段会变成只读状态
多个简单的组件嵌套,可构成一个复杂的复合组件,从而完成复杂的交互逻辑
var Panel = React.createClass({
render: function () {
return (
<div className="panel panel-default">
<PanelHead head={this.props.head}/>
<PanelBody body={this.props.body}/>
</div>
);
}
});
var PanelHead = React.createClass({
render: function () {
return (
<div className="panel-heading">
{this.props.head}
</div>
);
}
});
var PanelBody = React.createClass({
render: function () {
return (
<div className="panel-body">
{this.props.body}
</div>
);
}
});
ReactDOM.render(
<Panel
head="头部"
body="正文"
/>,
document.getElementById('app')
);
React中可以指定在组件的生命周期的不同阶段执行的函数
this.props
this.state
的初始值。this.props
和this.state
,返回一个组件props
或者state
,将要渲染之前调用,返回false
则不更新组件props
的时候调用var MessageBox = React.createClass({
getInitialState: function () {
console.log('MessageBox.getInitialState');
return {
count: 0,
}
},
getDefaultProps: function () {
console.log('MessageBox.getDefaultProps');
},
componentWillMount: function () {
console.log('MessageBox.componentWillMount');
},
componentDidMount: function () {
console.log('MessageBox.componentDidMount');
},
componentWillUnmount: function () {
console.log('MessageBox.componentWillUnmount');
},
shouldComponentUpdate: function (nextProp, nextState) {
console.log('MessageBox.shouldComponentUpdate');
if (nextState.count > 10) return false;
return true;
},
componentWillUpdate: function (nextProp, nextState) {
console.log('MessageBox.componentWillUpdate');
},
componentDidUpdate: function () {
console.log('MessageBox.componentDidUpdate');
},
killMySelf: function () {
ReactDOM.unmountComponentAtNode(document.getElementById('app'));
},
doUpdate: function () {
this.setState({
count: this.state.count + 1,
});
},
render: function () {
return (
<div>
<h1 > 计数: {this.state.count}</h1>
<button onClick={this.killMySelf}>卸载掉这个组件</button>
<button onClick={this.doUpdate}>手动更新一下组件</button>
<Submessage count={this.state.count}/>
</div>
)
}
});
var Submessage = React.createClass({
componentWillReceiveProps: function (nextProp) {
console.log('Submessage.componentWillReceiveProps');
},
shouldComponentUpdate: function (nextProp, nextState) {
console.log('Submessage.shouldComponentUpdate');
if (nextProp.count > 5) return false;
return true;
},
render: function () {
return (
<h3>当前计数是:{this.props.count}</h3>
)
}
});
ReactDOM.render(<MessageBox/>, document.getElementById('app'));
ReactDOM.unmountComponentAtNode 从DOM中移除已经挂载的React组件
给组件加上ref="xxx"
后,可在父组件中通过this.refs.xxx
获取该DOM元素
var Focus = React.createClass({
handleClick: function() {
this.refs.msg.focus();
},
render: function() {
return (
<div>
<input type="text" ref="msg" />
<input type="button" value="获得焦点"
onClick={this.handleClick} />
</div>
);
}
});
ReactDOM.render(
<Focus />,
document.getElementById('app')
);
var Suggestion = React.createClass({
getInitialState:function(){
return {}
},
handleChange: function () {
var value = this.refs.input.value;
$.ajax({
url: 'http://www.baidu.com/su',
type: 'get',
jsonp: 'cb',
dataType: 'jsonp',
data: {wd: value},
processData: true,
context:this,
success: function (result) {
var data = result.s;
data = data.map(function(item,index){
return <li key={index}>{item}</li>
});
this.setState({content:data});
}
})
},
render: function () {
return (
<div>
<input type="text" ref="input"
onChange={this.handleChange}/>
<ul>
{this.state.content}
</ul>
</div>
)
}
});
ReactDOM.render(<Suggestion></Suggestion>, document.getElementById('app'));
var express = require('express');
var app = express();
app.get('/jsonp',function(req,res){
var wd = req.query.wd;//得到关键字
var cb = req.query.cb;//得到回调函数的方法名
var result = {q:wd,p:false,s:[]};//拼结果对象
for(var i=0;i<10;i++)
result.s.push(wd+i);
//先设置响应头
res.setHeader('Access-Control-Allow-Origin',"*");
res.send(`${cb}(${JSON.stringify(result)})`);
});
app.listen(9090);
function ajax({url,type,data,processData,jsonp,dataType,context,success}){
var xhr = new XMLHttpRequest();
url+= '?';
var params = '';
if(processData)
for(var attr in data){
params += (attr+'='+data[attr]);
}
else
url+=data;
url+=params;
var method = 'jQuery_'+Date.now();
url += ('&'+jsonp+'='+method);
xhr.open(type,url,true);
xhr.onreadystatechange = function(){
if(xhr.readyState == 4 && /2\d{2}/.test(xhr.status)){
var response = xhr.responseText.match(/{[^{}]+}/)[0];
var jsonObj = JSON.parse(response);
success.bind(context)(jsonObj);
}
}
xhr.send();
}
公用抽取出来,让不同的组件共用同一部分逻辑,实现代码重用
var counterMix = {
getInitialState:function(){
return {count:0};
},
componentWillUpdate:function(){
console.log('componentWillUpdate');
},
handleClick:function(){
this.setState({count:this.state.count+1});
}
}
var Counter1 = React.createClass({
mixins: [counterMix],
render:function(){
return (
<div>
{this.state.count}
<button onClick={this.handleClick}>增加</button>
</div>
)
}
});
var Counter2 = React.createClass({
mixins: [counterMix],
render:function(){
return (
<div>
{this.state.count}
<button onClick={this.handleClick}>增加</button>
</div>
)
}
});
ReactDOM.render(<div>
<Counter1/>
<Counter2/>
</div>,document.getElementById('app'));
在index.html
引入插件
+ <script src="lib/react/react-with-addons.js"></script>
JS实现
var Input = React.createClass({
mixins:[React.addons.LinkedStateMixin],
getInitialState: function() {//获取初始状态
return {msg: '珠峰培训'};
},
render: function () {
var msg = this.state.msg;
return (
<div>
<input type="text" valueLink={this.linkState('msg')} />
<p>{msg}</p>
</div>
);
}
});
ReactDOM.render(<Input/>, document.getElementById('app'));
var Board = React.createClass({
getInitialState: function () {
return {
msg: '请输入',
messages:this.props.messages
};
},
render: function () {
return (
<div>
<h1>{this.props.title}</h1>
<input type="text" defaultValue={this.state.msg}
ref="txtMsg" onClick={this.clear}/>
<input type="button" value='发言' onClick={this.leaveMsg}/>
<ul>
{
this.state.messages.map(function (item, index) {
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
},
clear:function(){
this.refs.txtMsg.value = '';
},
leaveMsg: function (event) {
this.state.messages.push(this.refs.txtMsg.value);
//每次状态都是一个新的state对象
localStorage.setItem('messages',JSON.stringify(this.state.messages));
this.setState({
messages:this.state.messages
},function(){
this.refs.txtMsg.value = '';
});
}
})
var data = {
title: '珠峰留言版',
messages: JSON.parse(localStorage.getItem('messages'))||[]
}
ReactDOM.render(
<Board {...data}/>,
document.getElementById('app')
);