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文件就可以了。