1--react优势
组件化-便于分工、合作
虚拟DOM-性能高
跨平台-移动端
最强,即react核心:组件化、状态
2—react缺点
学习曲线特别陡
设计属性有点特别
3—react技术栈
react主体、webpack、flex、react-route、redux(view 层)、Mocha(测试)、Istanbul(覆盖率)、
4—JSX:
增强型的js语法—html代码可以直接放在js里、需要编译、babel
Ps:有且只有一个父元素;模板字符串
Babel和react通过Git Bash 安装过程:
$ bower install babel命令可以用于下载babel
$ bower install react命令可以用于下载react
小栗子:在div内渲染span元素
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( //向页面渲染东西,第一个参数为需要渲染的东西,第二个参数为在哪里渲染该东西 <span>666</span>, oDiv ); }; </script> </head> <body> <div id="div1"> </div> </body> </html>
5—组件
(1)定义组件—组件==class类
class 名字 extends React.Component{
render(){
return <span>666</span>;
}
}
(2)使用组件
跟标签一样使用
ReactDOM.render( <span>666</span>, oDiv ); ReactDOM.render( <Com/>, oDiv );
小栗子:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Comp extends React.Component{ //这里组件是用class的形式实现 //继承react的组件, //React.Component为帮助我们写组件的父类 //里面至少要有一个render()方法,返回自己需要的东西,作为组件,须在页面上能渲染出来 render(){ //render()当需要渲染组件时,需要告诉它渲染什么 return <span>666</span>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <Comp/>, oDiv ); }; </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Comp extends React.Component{ render(){ return <span>我的名字为{this.props.name},我今年{this.props.age}岁 </span>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <Comp name="blue" age="16" />, oDiv ); } </script> </head> <body> <div id="div1"> </div> </body> </html>
Ps:{}表示模板,需要渲染的东西放在该模板中
6--属性-不变的、状态-可变的
(1)状态是可变的
在构造函数constructor里面可以通过this.state{ }直接进行初始化;但在其他方法里面,则需要使用react自带的方法,即this.setState({ });
(2)事件大小写不能乱
onChange、onClick、、、、、
(3)绑定事件
onChange={this.fn.bind(this)}
(4)构造函数
当用constructor的时候,必须用super父类,即需要先完成父类函数里的构造,才能再完成自身函数的构造。constructor用于初始化状态。
小栗子の输入框改变的渲染:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Comp extends React.Component{ constructor(...args){ super(...args); //超类、父类,需先完成父类的构造函数,将接收到的参数都传给父类 this.state={value:''}; } fn(ev){ this.setState({ value:ev.target.value }); } render(){ return <div> <input type="text" onChange={this.fn.bind(this)} /> <span>{this.state.value}</span> </div>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <Comp/>, oDiv ); } </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子の点击显示隐藏:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <style media="screen"> .box{ 200px; height:200px; background: chartreuse; } </style> <script type="text/babel"> class ShowHide extends React.Component{ constructor(...args){ //构造函数,用于状态的初始化 super(...args); this.state={display:'block'}; } fn(){ //回调函数,用于事件处理,状态改变处理 this.setState({ display:this.state.display=='block'?'none':'block' }); } render(){ //渲染函数,将组件或虚拟dom渲染到真实的dom上,交给浏览器处理 return <div> <input type="button" value="显示隐藏" onClick={this.fn.bind(this)} /> <div className="box" style={{display:this.state.display}}></div> </div>; } } window.onload=function(){ //定义的组件拿来用 var oDiv=document.getElementById("div1"); ReactDOM.render( <ShowHide/>, //需要渲染的组件 oDiv //组件渲染的位置 ); }; </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子の时钟:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Clock extends React.Component{ constructor(...args){ super(...args); this.state={h:0,m:0,s:0}; var _this=this; setInterval(function(){ _this.tick(); },1000); } componentDidMount(){ //已经创建完了,再执行tick() this.tick(); } tick(){ var oDate=new Date(); this.setState({ h:oDate.getHours(), m:oDate.getMinutes(), s:oDate.getSeconds(), }); } render(){ return <div> <span>{this.state.h}</span>: <span>{this.state.m}</span>: <span>{this.state.s}</span> </div>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <Clock />, oDiv ); }; </script> </head> <body> <div id="div1"> </div> </body> </html>
7—组件-生存周期
componentWillMount() 创建之前
componentDidMount() 创建之后
componentWillUpdate() 更新之前
componentDidUpdate() 更新之后
componentWillUnmount() 卸载之前
componentWillReceiveProps() 组件参数更新
小栗子1:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Comp extends React.Component{ componentWillMount(){ console.log("即将创建完成"); } componentDidMount(){ console.log("刚刚创建完成"); } render(){ return <span>666</span>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <Comp />, oDiv ); } </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子2:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Comp extends React.Component{ componentWillUnmount(){ console.log("即将销毁"); } render(){ return <span>666</span>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); var i=0; document.onclick=function(){ i++; if(i%2){ ReactDOM.render( <Comp/>, oDiv ); }else{ ReactDOM.render( <div>qq</div>, oDiv ); } } } </script> </head> <body> <div id="div1"> </div> </body> </html>
8—组件重用、父子组件间通信
小栗子:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class ChildComp extends React.Component{ componentWillReceiveProps(){ console.log("参数更新了"); } render(){ return <span>{this.props.name}</span>; } } class ParentComp extends React.Component{ constructor(...args){ super(...args); this.state={i:0}; } fn(){ this.setState({ i:this.state.i+1 }); } render(){ return <div> <input type="button" value="click" onClick={this.fn.bind(this)}/> <ChildComp name={this.state.i} /> </div>; } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <ParentComp/>, oDiv ); }; </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子:
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script type="text/babel"> class Item extends React.Component{ //子组件 constructor(...args){ super(...args); } render(){ return <li>{this.props.value}</li>; } } class List extends React.Component{ //父组件 constructor(...args){ super(...args); this.state={arr:[12,6,8,9]}; } fn(){ this.setState({ arr:this.state.arr.concat([Math.random()]) }); } render(){ var result=[]; var arr=this.state.arr; /* for(var key in arr){ result.push(<Item value={arr[key]}/>); }*/ for(var i=0;i<arr.length;i++){ result.push(<Item key={i} value={arr[i]}/>); //key用于识别不同的标签,已经存在的就不用再创建了,重新利用,只要更新里面的内容即可 } return <ul> <input type="button" value="按钮" onClick={this.fn.bind(this)}/> {result} </ul> } } window.onload=function(){ var oDiv=document.getElementById("div1"); ReactDOM.render( <List />, oDiv ) } </script> </head> <body> <div id="div1"> </div> </body> </html>
9—react输出成组元素
首先将元素push进数组
arr.push(<Item/>);//Item为组件
arr.push(<Item/>);
arr.push(<Item/>);
然后,直接将数组渲染出来
<ul>
{arr}
</ul>
10—组件内的节点(Node)
一切对属性的修改,利用setState,激活重新渲染
ref参数,类似于id
refs内存在着所有节点
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="./js/react.js" charset="utf-8"></script> <script src="./js/react-dom.js" charset="utf-8"></script> <script src="./js/browser.js" charset="utf-8"></script> <script src="./js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class Title extends React.Component{ constructor(...args){ super(...args); } fn(){ /* alert(this.refs["s1"]);*/ /* var oS=this.refs["s1"]; oS.style.color="red";*/ $(this.refs['s1']).css('color','red'); } render(){ return <div> <input type="button" value="按钮" onClick={this.fn.bind(this)} /> <span ref="s1">666</span> </div>; } } $(function(){ ReactDOM.render( <Title/>, $('#div1')[0] ); }); </script> </head> <body> <div id="div1"> </div> </body> </html>
小栗子の拖拽(状态方式):
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <style media="screen"> .box {200px;height:200px;background:#CCC;position:absolute;} </style> <script type="text/babel"> class Drag extends React.Component{ constructor(...args){ super(...args); this.state={x: 0, y: 0}; } fn(ev){ var disX=ev.pageX-this.state.x; var disY=ev.pageY-this.state.y; var _this=this; document.onmousemove=function (ev){ _this.setState({ x: ev.pageX-disX, y: ev.pageY-disY }); }; document.onmouseup=function (){ document.onmousemove=null; document.onmouseup=null; }; } render(){ return <div style={{left: this.state.x+'px', top: this.state.y+'px'}} className="box" onMouseDown={this.fn.bind(this)}> 11111 </div>; } } $(function (){ ReactDOM.render( <Drag />, $('blue-view')[0] ); }); </script> </head> <body> <blue-view></blue-view> </body> </html>
Ps:$(function(){ }) 等价于 $(document).ready(function(){ })
(1)react只提供组件和状态,可以和原生及其他库配合使用
(2)组件内节点:
ref=”类似于id”
this.refs[‘ref名字’] //得到的即为原生对象
11—表单问题
(1)value值,表单中的默认值应该取defaultValue,这样输入框不会成为只读模式
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class UserLoginForm extends React.Component{ render(){ return <form action="http://baidu.com/" method="get"> 用户名:<input type="text" name="username" defaultValue={this.props.a} /> <input type="submit" value="提交" /> </form>; } } $(function(){ ReactDOM.render( <UserLoginForm a="blue" />, $("blue-view")[0] ); }) </script> </head> <body> <blue-view></blue-view> </body> </html>
(2)用checked问题,改为defaultChecked,否则就不能自由更改了
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class UserLoginForm extends React.Component{ render(){ return <form action="http://baidu.com/" method="get"> 用户名:<input type="text" name="username"defaultValue={this.props.a} /><br /> 是否接收邮件:<input type="checkbox" defaultChecked="true" /><br/> <input type="submit" value="提交" /> </form>; } } $(function(){ ReactDOM.render( <UserLoginForm a="blue" />, $("blue-view")[0] ); }) </script> </head> <body> <blue-view></blue-view> </body> </html>
12—阻止事件冒泡
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class TmpComp extends React.Component{ constructor(...args){ super(...args); } fn1(){ alert("父级"); } fn2(ev){ alert("子级"); ev.nativeEvent.stopImmediatePropagation();//阻止冒泡 } render(){ return <div onClick={this.fn1.bind(this)}> <div onClick={this.fn2.bind(this)}>666</div> </div> } } $(function(){ ReactDOM.render( <TmpComp />, $('blue-view')[0] ); }) </script> </head> <body> <blue-view> </blue-view> </body> </html>
13—组件间通信
(1)父级-->子级
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class Child extends React.Component{ constructor(...args){ super(...args); } render(){ return <div>{this.props.a}</div>; } } class Parent extends React.Component{ constructor(...args){ super(...args); this.a=12; } render(){ return <div> <div>aa</div> <Child a={this.a} /> <div>bbb</div> </div>; } } $(function(){ ReactDOM.render( <Parent />, $('blue-view')[0] ); }) </script> </head> <body> <blue-view></blue-view> </body> </html>
父级往子级放东西
(2)子级-->父级
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="js/browser.js" charset="utf-8"></script> <script src="js/react.js" charset="utf-8"></script> <script src="js/react-dom.js" charset="utf-8"></script> <script src="js/jquery-3.1.1.js" charset="utf-8"></script> <script type="text/babel"> class Child extends React.Component{ constructor(...args){ super(...args); this.num=66; } render(){ /*alert(this.props.cb);//测试子级的属性里是否有父级的cb*/ this.props.cb(this.num); //通过回调函数将子级里的num值传给父级的cb属性 return <div>{this.props.a}</div>; } } class Parent extends React.Component{ constructor(...args){ super(...args); this.a=12; } fn(num){ //父级的回调函数,接收num alert(num); } render(){ return <div> <div>aa</div> <Child cb={this.fn.bind(this)} /> <div>bbb</div> </div>; } } $(function(){ ReactDOM.render( <Parent />, $('blue-view')[0] ); }) </script> </head> <body> <blue-view></blue-view> </body> </html>
14—webpack
选择webpack原因:
(1)babel需实时编译,速度慢
(2)测试麻烦
(3)自己搭建服务器
(4)热更新
Webpack:
一种打包工具
(a)下载webpack工具:
(1)可以先安装淘宝镜像cnpm:
npm install cnpm -g --registry=https://registry.npm.taobao.org
(2) cnpm install –g webpack //webpack的cli环境
(3)cnpm install –g webpack-dev-server //开发用的服务器,webpack自带服务器,cli
(4)cnpm init 产生一个package.json文档
{ "name": "react_webpack", "version": "1.0.0", "main": "index.js", "dependencies": { "babel-cli": "^6.24.1", "babel-preset-env": "^1.4.0", "babel-preset-es2015": "^6.24.1", "vue": "^2.2.6", "webpack": "^2.4.1" }, "devDependencies": { "babel-cli": "^6.24.1", "css-loader": "^0.28.0", "style-loader": "^0.16.1" }, "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "sxt", "license": "ISC", "description": "" }
(b)各种依赖库:
Babel相关的库
(1)cnpm install babel-core //后台编译babel的工具
(2)cnpm install babel-core –save-dev 或者 cnpm install babel-core –D
此时package.json文档多了一个babel-core依赖库
{ "name": "hello", "version": "1.0.0", "main": "index.js", "dependencies": { "babel-cli": "^6.24.1", "babel-preset-env": "^1.4.0", "babel-preset-es2015": "^6.24.1", "vue": "^2.2.6", "webpack": "^2.4.1" }, "devDependencies": { "babel-cli": "^6.24.1", "babel-core": "^6.24.1", "css-loader": "^0.28.0", "style-loader": "^0.16.1" }, "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "sxt", "license": "ISC", "description": "" }
(3)cnpm install babel-preset-es2015 –D //babel对于2015的一个预设,可以理解为简单的configure
(4)cnpm install babel-loader -D //帮助babel加载的一个环境 ,babel加载器
Webpack本身:
cnpm install webpack –D //webpack的本地依赖库
cnpm install webpack-dev-server –D //webpack服务器的本地依赖库,开发库,可以实时更新热更新
cnpm install babel-preset-react –D //babel对react的预设
cnpm install react –D //react库本身
cnpm install react-dom –D //react-dom本身
cnpm install react-hot-loader –D //react热更新
cnpm install style-loader –D
cnpm install css-loader -D
所有需要的package.json文档:
{ "name": "react_webpack", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo "Error: no test specified" && exit 1" }, "author": "sxt", "license": "ISC", "devDependencies": { "babel-core": "^6.24.1", "babel-loader": "^7.0.0", "babel-preset-es2015": "^6.24.1", "babel-preset-react": "^6.24.1", "css-loader": "^0.28.1", "react": "^15.5.4", "react-dom": "^15.5.4", "react-hot-loader": "^1.3.1", "style-loader": "^0.17.0", "webpack": "^2.5.1", "webpack-dev-server": "^2.4.5" } }
Ps:上面各种依赖库可以直接用cnpm install 即可下载安装,即把node_modules文件夹删掉,保留package.json文件,在命令行输入cnpm install,则会根据package.json文件自动下载该文件内用到的依赖。
(c)webpack的配置文件
(1)入口 entry
(2)出口output
(3)source-map
(4)指定loaderss
devtool: 开发工具
Webpack.config.js //webpack的配置文件
module.exports={ entry:'./index.js', output:{ path:__dirname, filename:'bundle.js' }, devtool:'source-map', module:{ loaders:[ {test:/.css$/,loader:'style!css'}, {test:/.js$/,loader:'react-hot-loader!babel-loader',exclude:/node_modules/}, ] } };
.babelrc //babel的预设文件
{ presets:[['es2015'],['react']] }
启动服务器命令:
方法1:直接在相应文件夹目录下输入:webpack
可以直接将文件打包。利用webpack打包,可以理解为将各种依赖库都重新放到一个新的文件bundle.js中了,在我们的html中,只需要引入这一个文件,省得引入那么多依赖库了。作为入口的index.js直接跟react一样写
命令行中:webpack-dev-server –hot 可以实现页面的实时更新热更新
方法2:
例子:
1.html
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <script src="bundle.js"></script> <script type="text/babel"> window.onload=function(){ var oView=document.getElementsByTagName('blue-view')[0]; ReactDOM.render( <Test />, oView ) } </script> </head> <body> <blue-view></blue-view> </body> </html>
Index.js:
const React=require('React'); class Test extends React.Component{ constructor(...args){ super(...args); this.state={value:''}; } fn(){ this.setState({ value:this.refs['txt1'].value }); } render(){ return <div> <input ref="txt1" type="text" onChange={this.fn.bind(this)} /> <span>{this.state.value}</span> </div>; } }
其中,bundle.js是由webpack打包得到的,可以理解为webpack将.json文件中所需要用到的依赖都整合到了bundle.js,这样只有引入一个bundle.js文件就可以了。