<< React Native 入门与实战>>----第2章 React Native开发基础

时间:2021-06-24 08:22:31

2.1 flexbox布局
flexbox是React Native应用开发不可少的内容

 2.1.2 布局模型

flexbox布局由伸缩容器和伸缩项目组成。任何一个元素都可以指定为flexbox布局,其中设为display:flex或display:inline-flex的元素称为伸缩容器,伸缩容器的子元素称为伸缩项目,伸缩项目使用伸缩布局模型来排版

<< React Native 入门与实战>>----第2章 React Native开发基础

上面图片引用网址:http://www.w3cplus.com/css3/flexbox-basics.html默认情况下伸缩容器由两根轴组成,主轴(main axis)和交叉轴(cross axis),其中主轴的开始位置叫做main start,结束位置叫main end,交叉轴的开始位置叫cross start,结束位置叫cross end,伸缩项目在主轴上占据的空间叫main size,在交叉轴上占据的空间叫cross size,根据设置情况的不同,主轴既可以是水平轴,也可以是垂直轴,默认情况下伸缩项目总是沿着主轴,从主轴位置以主轴结束位置进行排列,flexbox还在草稿状态,需要加上各个浏览器的私有前缀,即-wekit,-moz,mx,-o等

2.1.3 伸缩容器属性
支持的属性有:

  • display
  • flex-direction
  • flex-wrap
  • flex-flow
  • justify-content
  • align-items
  • align-content

    下面介绍这几个属性

    1、display 属性用于指定元素是否为伸缩容器,其语法为display:flex | inline-flex HTML代码为

    <span class="flex-container"></span>

属性值的含义:
flex:这个值用于产生块级伸缩容器,示例CSS代码如下:
.flex-container{
display:flex;
}
inline-flex用于产生行内级伸缩容器,示例CSS代码如下:
.flex-container{
display:inline-flex;
}

2、flex-direction:该属性用于指定主轴的方向语法
flex-dirction:row|row-reverse|column|column-reverse
html代码:

<span class ="flex-container">
<span class="flex-item">1</span>
<span class="flex-item">2</span>
<span class="flex-item">3</span>
</span>

row(默认值):从左向右排列
.flex-container{
display:flex;
flex-direction:row;
}
row-reverse:从右向左排列
column:从上向下排列
column从下向上排列

3、flex-wrap主要用于指定伸缩容器的主轴线空间不足的情况下,是否换行以及如何换行,语法为
flex-wrap:nowap|wrap|wrap-reverse
HTML代码如下:

    <span class ="flex-container">
<span class="flex-item">1</span>
<span class="flex-item">2</span>
<span class="flex-item">3</span>
<span class="flex-item">4</span>
<span class="flex-item">5</span>
</span>

nowrap(默认值):即使空间不足,伸缩容器也不允许换行

.flex-container{
display:flex;
flex-direction:row;
flex-wrap:nowrap;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

wrap:不允许换行,换行方向从上到下
wrap-reverse:允许换行,则换行的方向为从下到上(和wrap相关)下面会是三个上面是两个
flex-flow:该属性是flex-direction和flex-wrap属性的缩写版本,默认是row nowrap
5、justify-content:该属性用于定义伸缩项目沿主轴线的对齐方式,其

语法:justify-content:flex-start|flex-end|center|space-between|space-around

HTML代码如下:

  <span class="flex-container">
<span class="flex-item">1</span>
<span class="flex-item">2</span>
<span class="flex-item">3</span>
</span>

下面介绍这5个属性值的含义:
flex-start(默认值):伸缩项目向主轴线的起始位置靠齐

.flex-container{
display:flex;
flex-direction:row;
justify-content:flex-start;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

flex-end:伸缩项目向主轴线的结束位置靠齐
center:伸缩项目向主轴线的中间位置靠气
space-between:伸缩项目会平均地分布在主轴线里,第一个伸缩项目在主轴线的开始位置,最后一个伸缩项目在主轴线的终点位置。
space-around:伸缩项目会平均分布在主轴线里,两端保留一半的空间

6、align-items:该属性用来定义伸缩项目在伸缩容器的交叉轴上的对齐方式(就是垂直方向)
align-items:flex-start| flex-end | center | baseline | stretch
HTML代码如下:

<span class="flex-container">
<span class="flex-item" item="item1">1</span>
<span class="flex-item" item="item2">2</span>
<span class="flex-item" item="item3">3</span>
</span>

flex-start(默认值):伸缩项目向交叉轴的起始位置靠齐就是顶部对齐:css

.flex-container{
display:flex;
flex-direction:row;
align-items:flex-start;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

flex-end:向交叉轴结束位置靠齐(底部对齐)
center:中间对齐
baseline:伸缩项目根据它们的基线对齐(这个就是每一个里面的大小不同的时候,根据第一个的底部对齐)
strectch(默认值):伸缩项目在交叉轴方向拉伸填充整个伸缩容器,要看到这个伸缩项目是不能设置高度的,就是不设置height,就是垂直方向填充满

7、align-content 该属性主要用来调整伸缩项目出现换行后在交叉轴的对齐方式,类似于伸缩项目在主轴上使用justify-conent,其语法为:
align-content:flex-start | flex-end | center | space-between | space-around | stretch

HTML代码如下:

  <span class="flex-container">
<span class="flex-item">1</span>
<span class="flex-item">2</span>
<span class="flex-item">3</span>
</span>

说明 :flex-wrap:wrap这个一定要开启,且它在出现换行的情况才能看到效果,下面提到所有伸缩项目所在的行

flex-start(默认值):伸缩项目向交叉轴的起始位置对齐,CSS代码:

.flex-container{
display:flex;
flex-direction:row;
flex-wrap:wrap;
align-content:flex-start;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

flex-end:伸缩项目结束位置对齐
center:中间位置对齐
space-between:伸缩项目在交叉轴中平均分布换行的上部分顶部对齐,换行的下部份底部对齐;
space-around:在交叉轴中平均分布,且在两边各有一半的空间,就是平均分布,顶部有空间,底部也有空间平均分布
stretch(默认值)伸缩将会在交叉轴上伸展以占用剩余的空间:就是上半部分没有换行的部分,占用剩余空间,并居中显示

2.1.4 伸缩项目属性还有以下几种:

  • order
  • flex-grow
  • flex-shrink
  • flex-basis
  • flex
  • align-self

self:主要用于定义项目的排列顺序,数据越小,排列越靠前,默认值为0,语法为:
HTML代码:

  <span class="flex-container">
<span class="flex-item item1">1</span>
<span class="flex-item item2">2</span>
<span class="flex-item item3">3</span>
<span class="flex-item item4">4</span>
<span class="flex-item item5">5</span>
</span>

CSS代码如下:

.flex-container{
display:flex;
flex-direction:row;
flex-wrap:wrap;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

.item5{
order:-1;
}

所有最后一个会排在第一个

2、flex-grow:伸缩项目的放大比例,默认为0,即如果存在剩余空间,也不放大,如果所有伸缩项目的flex-grow设置为1,那么每个伸缩项目将设置为一个大小相等的剩余空间,如果你将其中一个伸缩项的flex-grow值设置为2,那么这个伸缩项目所占的剩余空间是其他伸缩项目所占剩余空间的两倍:
更改上面的
.item5{
flex-grow:1; // 2
}

3、flex-shrink:定义伸缩项目的收缩能力默认值为1:
.item5{
flex-shrink:3;
}
item5在元素空间不足的情况下,缩小为其他元素大小的1/3;
4、flex-basis :该属性用于设置伸缩项目的基准值,剩余的空间按比率进行伸缩:
flex-basis:lenght|auto 默认为auto
5、flex:该属性是flex-grow、flex-shrink和flex-basis这3个属性的缩写:其语法如下
flex:none |flex-grow flex-shrink flex-basis
其中第二个参数和第三个参数(flex-shrink和flex-basis)可选参数,默认值为0 1 auto
在上面的例子中把.item3{flex:1}该元素就会把伸缩容器的剩余空间占满,其本质就等于flex-grow:1。该属性有两个快捷值:auto (1 1 auto)和none (0,0 auto)
6、align-self 该属性用于设置单独的伸缩项目在交叉轴上的对齐方式(垂直方向),会覆写默认的对齐方式,其语法如下:
align-self:auto|flex-start | flex-end| center|baseline|stretch
HTML代码如下:

  <span class="flex-container">
<span class="flex-item item1">1</span>
<span class="flex-item item2">2</span>
<span class="flex-item item3">3</span>
</span>

auto:伸缩项目按钮照自身设置宽高显示,如果没有设置,则按stretch来计算其值,示例代码如下:

.flex-container{
display:flex;
flex-direction:row;
flex-wrap:wrap;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

.item3{
align-self:auto;
}

flex-start:伸缩项目向交叉轴的开始位置靠齐
flex-end:结束位置靠齐.item3{align-self:auto;}
center:中心位置靠齐:
baseline:伸缩项目按基线对齐:

.flex-container{
display:flex;
flex-direction:row;
width:200px;
height:150px;
}

.flex-item{
width:50px;
height:50px;
}

.item1{
align-self:baseline;
font-size:40px;
}

.item2{
align-self:baseline;
font-size:30px;
}

.item3{
align-self:baseline;
font-size:20px;
}

stretch:占满伸缩容器,只有在不设置高度的情况下才能看到效果。

2.1.5 在React Native中使用flexbox

React Native将web中的flexbox布局引入进来,React Native目前还支持flexbox的如下属性:

  • alignItems
  • alignSelf
  • flex
  • flexDirection
  • flexWrap
  • justifyContent

1、alignItems:该属性的用法同前面的align-items,区别在于它需要用驼峰拼与法,其语法如下:
alignItems: flex-start| flex-end| center| stretch
2、alignSelf:语法同align-self,语法如下:
alignSelf:auto|flex-start|flex-end|center|stretch
3、flex 语法同:flex:number
4、flexDirection语法同flex-direction:row|column默认是column
5、flexWrap: flexWrap:wrap|nowrap
6、justifyContent:flex-start|flex-end|center|space-between|space-around

2.1.6实例

 我们用flexbox布局来实现一个标准的盒子模型,对于盒子模型,用过的同学都比较熟悉,它是css中排版布局的重要方法:它包括的属性有margin、border和padding等

下面看一下React Native中的主要代码实现:

'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;
var BoxStyles = StyleSheet.create({
"height50": {
height: 50,
},
"height400": {
height: 400,
},
"height300": {
height: 300,
},
"height200": {
height: 200,
},
"height100": {
height: 100,
},
"width400": {
width: 400,
},
"width300": {
width: 300,
},
"width200": {
width: 200,
},
"width100": {
width: 100,
},
"bgred": {
backgroundColor: "#6AC5AC",
},
"bggreen": {
backgroundColor: "#414142",
},
"bgyellow": {
backgroundColor: "#D64078",
},
"box": {
flexDirection: "column",
flex: 1,
position: "relative",
},
"label": {
top: 0,
left: 0,
paddingTop: 0,
paddingRight: 3,
paddingBottom: 3,
paddingLeft: 0,
position: "absolute",
backgroundColor: "#FDC72F",
},
"top": {
justifyContent: "center",
alignItems: "center",
},
"bottom": {
justifyContent: "center",
alignItems: "center",
},
"right": {
width: 50,
justifyContent: "space-around",
alignItems: "center",
},
"left": {
width: 50,
justifyContent: "space-around",
alignItems: "center",
},
"heightdashed": {
bottom: 0,
top: 0,
right: 20,
borderLeftWidth: 1,
position: "absolute",
borderLeftColor: "#FDC72F"
},
"widthdashed": {
bottom: 25,
left: 0,
right: 0,
borderTopWidth: 1,
position: "absolute",
borderTopColor: "#FDC72F"
},
"yellow": {
color: "#FDC72F",
fontWeight:"900",
},
"white": {
color: "white",
fontWeight:"900",
},
"margginBox":{
"position": "absolute",
"top": 100,
"paddingLeft":7,
"paddingRight":7,
},
"borderBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"paddingBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"elementBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"measureBox":{
flex: 1,
flexDirection: "row",
justifyContent: "flex-end",
alignItems:"flex-end"
}
})
var BoxContainer = React.createClass({
render:function(){
return (
<View style={[BoxStyles.margginBox]} ref="lab1">
<View style={[BoxStyles.box,BoxStyles.height400,BoxStyles.width400]}>
<View style={[BoxStyles.top,BoxStyles.height50,BoxStyles.bgred]}>
<Text style={BoxStyles.yellow}>top</Text></View>
<View style={[BoxStyles.borderBox]}>
<View style={[BoxStyles.left,BoxStyles.bgred]} >
<Text style={BoxStyles.yellow}>left</Text></View>
<View style={[BoxStyles.box,BoxStyles.height300]}>
<View style={[BoxStyles.top,BoxStyles.height50,BoxStyles.bggreen]}>
<Text style={BoxStyles.yellow}>top</Text></View>
<View style={[BoxStyles.paddingBox]}>
<View style={[BoxStyles.left,BoxStyles.bggreen]} >
<Text style={BoxStyles.yellow}>left</Text></View>
<View style={[BoxStyles.box,BoxStyles.height200]}>
<View style={[BoxStyles.top,BoxStyles.height50,BoxStyles.bgyellow]}>
<Text style={BoxStyles.yellow}>top</Text></View>
<View style={[BoxStyles.elementBox]}>
<View style={[BoxStyles.left,BoxStyles.bgyellow]} >
<Text style={BoxStyles.yellow}>left</Text></View>
<View style={[BoxStyles.box,BoxStyles.height100]}>
<View style={[BoxStyles.label]}>
<Text style={BoxStyles.white}>element</Text></View>
<View style={[BoxStyles.widthdashed]} ></View>
<View style={[BoxStyles.heightdashed]} ></View>
<View style={[BoxStyles.measureBox]} >
<View style={[BoxStyles.right]}>
<Text style={[BoxStyles.yellow]}>height</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50]}>
<Text style={BoxStyles.yellow}>width</Text></View>
</View>
<View style={[BoxStyles.right,BoxStyles.bgyellow]}><Text style={BoxStyles.yellow}>right</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50,BoxStyles.bgyellow]}>
<Text style={BoxStyles.yellow}>bottom</Text></View>
<View style={[BoxStyles.label]}>
<Text style={BoxStyles.white}>padding</Text></View>
</View>
<View style={[BoxStyles.right,BoxStyles.bggreen]}><Text style={BoxStyles.yellow}>right</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50,BoxStyles.bggreen]}>
<Text style={BoxStyles.yellow}>bottom</Text></View>
<View style={[BoxStyles.label]}><Text style={BoxStyles.white}>border</Text></View>
</View>
<View style={[BoxStyles.right,BoxStyles.bgred]}>
<Text style={BoxStyles.yellow}>right</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50,BoxStyles.bgred]}>
<Text style={BoxStyles.yellow}>bottom</Text></View>
<View style={[BoxStyles.label]} ><Text style={BoxStyles.white}>margin</Text></View>
</View>
</View>
)
}
})
AppRegistry.registerComponent('Box', () => BoxContainer);

可以看到在React-Native中,全部代码都是由javaScript来完成的。
可以在xcode中看到运行效果
在上面的示例中,HTMl5代码涉及的属性如下:

  • display
  • flex-direction
  • flex
  • justify-content
  • align-items

    React Native中涉及的属性如下:

  • justifyContent
  • alignItems
  • flex
  • flexDirection

    下面分别从样式、元素和书写格式这3个方面来简单介绍HTML5与React Native的差异
    样式。HTML5上的写法为

.marginBox{
position:absolute;
top:100px;
padding-left:7px;
padding-right:7px;
}

React Native上的写法为:

"margginBox":{
"position":"absolute",
"top":100,
"paddingLeft":7,
"paddingRight":7,
}

元素,HTML5代码如下:

<span class = "marginBox">
<span class="box height400 widht 400">
<span class="label">margin</span>

React Native代码如下:

<View style={[BoxStyles.label]}>
<Text style={BoxStyles.white}>margin</Text>
</View>
</View>
</View>

从上面 我们可以看出HTML5元素的显示层级是绝对定位层级较高,而React Native中的显示层级是后面比前面的高

书写格式的差异:

  • HTML以分号(;)结尾,React Native以逗号(,)结尾。
  • HTML5中的key、value都不加引号,React Native中属于JavaScript对象,如果value为字符串,需要加引号引起来,并且key值中间不能出现”-“,一定要转为驼峰命名方式。
  • HTML5中,value值为数字时,需带单位,React Native中则不用带。

2.2 React中的JSX

首先,我们先认识下React,React由ReactJs与React Native组成,其中ReactJs是FaceBook开源的一个前端框架,React Native是ReactJs思想在native上的体现。

2.2.1 JSX入门

我们先从hello world开始,下面是基于JSX写的一段代码:

var component = React.createClass({
render:function(){
return <div> hello world</div>
}
});

var component = React.createClass({
render:function(){
return Rect.createElement('div',null,'hello world')
}
});
什么是JSX呢,只是一个语法,允许开发者在javascript中书写html语法,最后,每个html标签都转化为javascript代码来运行

1、环境
jsx必须借助ReactJs环境才能运行,在编写jsx代码之前,需要先加载ReactJs文件

    <script src="./build/react-0.13.3.js"></script>
<script src="./build/JSXTransformer-0.13.3.js"></script>

2、载入方式
内联方式的载入,语法

<script type="text/jsx">
React.render(
<h1> hello,world!</h1>,
document.getElementById('example')
);
</scipt>

外联方式的载入,将下面的代码单独放在一个helloworld.jsx的文件中

hellworld.jsx
React.render(
<h1>Hello,World</h1>,
document.getElementById('example')
);
// 然后在页面引入helloworld.jsx文件:
<script text="text/jsx" src="helloworld.jsx"></script>

3、标签
jsx标签其实就是html标签,如

   <h1>hello world</h1>

像xml文件的书写一样,直接写即可,然而还有一类标签是html所没有的,但是我们也可以使用,那就是ReactJS创建的组件类标签,显示代码如下:

var Hello = React.createClass({
render:function(){
return <div>Hello</div>;
}
});
React.render(
<Hello/>,
document.getElementById('container')
)

在上面的代码中,我们创建了一个Hello的组件,此时需要我们像使用HTML标签一样,通过<hello/>的方式引入进来,不过有一点需要注意的是,ReactJS约定自定义组件标签首字母一定要大写,这样便于区分是组件标签还是HTML标签。

4、转换
Jsx的代码最终会转换为javascript代码才能运行在浏览器上。
比如:我们写了一段代码:

<h1>hello world</h1>

解析器会将转化为

React.createElement("h1",null,"Hello,ReactJs")

其实我们每写一个标签,就相当于调用一次React.createElement方法并最后返回一个ReactElement对象给我们。
现在我们看一下React.createElement方法中的这些参数分别代表什么意思?

React.createElement(
string/ReactClass type,
[object props],
[children...]
)

方法的第一个参数可以是一个字符串,表示一个HTML标准内的元素,或者 是一个ReactClass类型的对象,表示我们之前封装好的自定义组件,第二个参数是一个对象,或者说是字典,它保存了这个元素的所有固有属性(即传入后基本不会改变的值),第三个参数就是元素的子元素。
5、执行javascript表达式
jsx是怎么执行javascript代码的
下面我们定义一个变量:

var msg = "hello reactjs";

然后在jsx中调用变量

<h1>{msg}</h1>

解析完后的结果如下;

var msg="hello Reactjs";
React.createElement("h1",null,msg)

可以看出,jsx运行javascript代码,需要将表达式用{}括起来。

6、注释
jsx的注释单行注释
// 单行注释
/**
多行注释
**/

7、属性
我们知道,在HTML可以通过标签上的属性来改变当前的元素的样式,在jsx中也可以使用该功能:

var msg=<h1 width="100px">Hello ReactJs!</h1>;

该代码转化后的结果为:

var msg=React.creatElement("h1",{width:"100px","Hello,ReactJs"});

8、延展属性
jsx支持ES6的功能

9、自定义属性
自定义属性便是自己定义的一些属性,但是在真正的页面渲染后,它不一定显示在页面上,那么什么样的自定义属性才能渲染在页面上呢?,HTML5给出了方案,凡是以data-开关的自定义属性,在页面渲染后均可以显示在页面上,下面看例子:
我们在jsx中进行如下的书写:

    var Hello =<h1 height="100" data-text="test" text="test">Hello Reactjs</h1>;
React.render(Hello,document.getElementById('example'));

最后在页面上只显示了data-test,其他自定义属性会被忽略。

10、显示HTML代码
有时候我们需要显示一段html字符串,而不是HTML节点,_html属性上场了,看下面的例子:

<div>{{_html:'<h1>hello,ReactJs!!</h1>'}}</div>

11、样式使用
jsx中的输入

<div style={{color:'#ff0000',fontSize:'14px'}}>Hello </div>

解析后的代码

React.createElement("h1",{style:{color:'#ff0000',fontSize:'14px'}},"Hello,ReactJs");

下面我们要析一下上面的代码,第一个大括号是JSX语法,第二个大括号是javaScript对象,我们把需要定义的样式都以对象的方式写在这个大括号里,需要注意的是,我们要将属性转为驼峰命名格式,若不转的话,需要加引号括起,比如'font-size':'13px'或者fontSize:’13px’这其实就是javaScript中的json的书写,当然也可以通过className==xxx的方式引入样式,切记是className不是class

12、事件绑定
下面看看jsx怎么绑定事件的代码:

functin testClick(){
alert('testClick');
}
var app=<button onClick={testClick.bind(this)} style=
{{
backgorundColor:'#ff0000',
fontSize:'28px',
width:'200px',
height:'100px'
}}
>hello,ReactJs</button>
React.render(
app,
document.getElementById('example')
);

这个功能看起来和在HTML中使用的绑定事件是一个的,这里,事件名称一定要采用驼峰命名方式,其实如果给绑定事件传参数,可以这样写onClick={testClick.bind(this,'hello')}hello就是要传入的参数。

2.2.2 JSX实战ReactJs
1、ReactJs简介
2、组件介绍
我们先从一个简单的组件开始:

    var HelloMessage=React.createClass({
render:function(){
return <div>Hello {this.props.name}</div>;
}
});

React.render(
<HelloMessage name="John"/>,
document.getElementById('example')
)

这是一个简单的HelloMessage组件,下面来解释一下:

  • React是全局对象,ReactJS是所有顶层API都挂在这个对象下
  • React.createClass是ReactJS用来创建组件类的方法。
  • render是一个组件级的API,是React.createClass内部最常用的API,该方法主要用来返回组件结构,
  • React.render是最基本方法,是用于将模板转为HTML语言,并将转化后的DOM结构插入到指定的DOM节点上,参数描述如下:
ReactComponent render(
ReactElement element,// ReactJS组件
DOMElement container,// 页面中的DOM容器
[function callback]// 插入后的回调
)

上面的代码用文字描述就是,先通过React.createClass来创建组件类,然后调用render方法输出组件的DOM结构,最后调用React.render将组件插入在id为example的节点上。

3、组件的生命周期

var List=React.createClass({
// 1、创建阶段
getDefaultProps:function(){
// 在创建类的时候被调用
console.log("getDefaultProps");
return {};
},
// 2、实例化阶段
getInitialState:function(){
// 获取this.state的默认值
console.log("getInitialState");
return{};
},
componentWillMount:function(){
// 在render之前调用此方法
// 业务逻辑的处理都应该放在这里,如对state的操作等
console.log("componentWillMount");
},
render:function(){
// 渲染并返回一个虚拟DOM
console.log("render");
return (<div>Hello {this.props.name}</div>);
},
componentDidMount:function(){
// 该方法发生在render方法之后,该方法中,ReactJS会使用render方法返回虚拟DOM对象来创建真实的DOM结构
console.log("componentDidMount");
},
// 3、更新阶段
componentWillRecieveProps:function(){
// 该方法发生在this.props被修改或者父组件调用setProps()方法之后
console.log("componentWillRecieveProps");
},
shouldomponentUpdate:function(){
// 是否需要更新
console.log("shouldomponentUpdate");
return true;
},
componentWillUpdate:function(){
// 将要更新
console.log("componentWillUpdate");
},
componentDidUpdate:function(){
// 更新完比
console.log("componentDidUpdate");
},
// 4、销毁阶段
componentWillUnmount:function(){
// 销毁时被调用
console.log("componentWillUnmount");
}
})
  • 创建阶段:即调用React.createClass的时候,这个阶段只会触发一个getDefaultProps方法,并方法返回一个对象,并缓存下来,然后与父组件指定的props对象合并,最后赋值给this.props作为该组件的默认属性。props它是一个对象用来接收外面传来的参数,组件内部不允许修改自己的props的属性的,,只能通过父组件来修改,上面的getDefaultProps方法是处理props的默认值。
  • 实例阶段:
    getInitialState。初始化组件的state的值,其返回值会赋值给组件this.state的属性。
    state它是组件的属性,主要用来存储组件自身需要的数据,它是可以改变的,它的每次改变都会引发组件的更新,这也是React中的关键之一,每次数据的更新都是通过修饰state属性的值,然后ReactJS内部会监听state属性的变化,一旦发生变化,就是主动触发组件的render方法来更新DOM结构。
    虚拟DOM,它是Reactjs提出的一个概念,是将真实的DOm结构映射成一个json数据结构
  • 更新阶段
    componentWillReceiveProps(object nexProps)
    shouldComponentUpate(nextProps,nextStat)
    componentWillUdate(nextProps,nextStat)

4、组件之间的通信
先创建一个父类组件Parent,它内部调用的是一个叫Child的子组件,并将接收到的外部参数name传递给子组件的child,先创建父类组件Parent:

var Parent=React.createClass({
click:function(){
this.refs.child.getDOMNode().style.color="red";
},
render:function(){
return (
<div onClick={this.click}>
parent is:
<Child name={this.props.name} ref="child"></Child>
</div>
);
}
});
var Child=React.createClass({
render:function(){
return <span>{this.prop.name}</span>
}
});

最后通过React.render方法将组件渲染到页面上

React.render(<Parent name='React'/>,document.getElementById('container'));
这里组件之间的组合关系是一层套一层,像HTML中的DOM结构一样,所以用ReactJs开发的应用就比较清晰了
  • 子组件调用父组件的方法,子组件要拿到父组件的属性,需要通过this.props方法,代码中的this.props.name便是Child组件从Parent组件拿到name属性的
  • 父组件调用子组件的方法,那就是ref,这个属性就像给组件起了个名字一样,子组件被设置ref的值之后,父组件便可以通过this.ref.xxx来获取到子组件了,上面代码的意思就是父组件被点击的时候,会先获取子组件的元素,然后将子组件元素的文字颜色改成红色。

5.虚拟DOM(只更新有变化的dom)
- 原生组件的创建方式

var root = <ul>
<li>ctrip</li>
<li><ul><li>elong</li></ul></li>
</ul>

// 主要用来看输出虚拟DOM结构
console.log(root);

// javascript代码的实现
var ctrip = React.createElement('li',null,'ctrip');
.....
  • 自定义组件的创建方式
var Ctrip = React.createClass({
render:function(){
return (
<ul>
<li>ctrip</li>
<li>{this.props.children}</li>
</ul>
)
}
});
......

下面的是验证React的Diff算法,这里面就省略了,就是差异化更新,可以去看http://calendar.perfplanet.com/2013/diff

6、实战下面我们用JSX来实现BoxApp的效果,index.html,首先介绍一下HTML5主要代码:

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
.height50 {
height: 50px;
}

.height400 {
height: 400px;
}

.height300 {
height: 300px;
}

.height200 {
height: 200px;
}

.height100 {
height: 100px;
}

.width400 {
width: 400px;
}

.bgred {
background-color: #6AC5AC;
}

.bggreen {
background-color: #414142;
}

.bgyellow {
background-color: #D64078;
}

.box {
display: flex;
flex-direction: column;
flex: 1;
position: relative;
color: #FDC72F;
line-height: 1em;
}

.label {
top: 0;
left: 0;
padding: 0 3px 3px 0;
position: absolute;
background-color: #FDC72F;
color: white;
line-height: 1em;
}

.top {
width: 100%;
justify-content: center;
display: flex;
align-items: center;
}

.bottom {
width: 100%;
display: flex;
justify-content: center;
align-items: center;
}

.right {
width: 50px;
display: flex;
justify-content: space-around;
align-items: center;
}

.left {
width: 50px;
display: flex;
justify-content: space-around;
align-items: center;
}

.heightdashed {
position: absolute;
right: 20px;
height: 100%;
border-left: 1px solid #FDC72F;
}

.widthdashed {
position: absolute;
left: 0px;
width: 100%;
bottom: 24px;
border-top: 1px solid #FDC72F;
}

.margginBox {
position: absolute;
top: 100px;
padding-left: 7px;
padding-right: 7px;
}

.borderBox {
flex: 1;
display: flex;
justify-content: space-between;
}

.paddingBox {
flex: 1;
display: flex;
justify-content: space-between;
}

.elementBox {
flex: 1;
display: flex;
justify-content: space-between;
}

.measureBox {
flex: 1;
display: flex;
justify-content: flex-end;
align-items: flex-end;
}

</style>
</head>
<body>
<div id="container"></div>
<script src="./build/react-with-addons-0.13.3.js"></script>
<script src="./build/JSXTransformer-0.13.3.js"></script>
<script type="text/jsx">
// JSX代码如下
var Box = React.createClass({
render:function(){
var parentClass = "box "+this.props.width+" "+ this.props.height;
var topClass = "top height50 "+this.props.classBg;
var leftClass = "left "+this.props.classBg;
var rightClass = "right "+this.props.classBg;
var bottomClass = "bottom height50 "+this.props.classBg;
return (
<span className= {parentClass}>
<span className="label">{this.props.boxName}</span>
<span className={topClass}>top</span>
<span className={this.props.childName}>
<span className={leftClass}>left</span>
{this.props.children}
<span className={rightClass}>right</span>
</span>
<span className={bottomClass}>bottom</span>
</span>
)
}
})
var MargginBox = React.createClass({
render:function(){
return (
<span className="margginBox">
<Box childName="borderBox" height="height400" width="width400" boxName="margin" classBg="bgred">{this.props.children}</Box>
</span>
)
}
})
var BorderBox = React.createClass({
render:function(){
return (
<Box childName="paddingBox" height="height300" width="width300" boxName="border" classBg="bggreen" >{this.props.children}</Box>
)
}
})
var PaddingBox = React.createClass({
render:function(){
return (
<Box childName="elementBox" height="height200" width="width200" boxName="padding" classBg="bgyellow" >{this.props.children}</Box>
)
}
})
var ElementBox = React.createClass({
render:function(){
return (
<span className="box height100 ">
<span className="label">element</span>
<span className="widthdashed"></span>
<span className="heightdashed"></span>
<span className="measureBox" >
<span className="right">height</span>
</span>
<span className="bottom height50">width</span>
</span>
)
}
})
var BoxContainer = React.createClass({
render:function(){
return (
<MargginBox>
<BorderBox>
<PaddingBox>
<ElementBox>
</ElementBox>
</PaddingBox>
</BorderBox>
</MargginBox>
)
}
})
React.render(<BoxContainer/> ,document.getElementById("container"));

</script>
</body>
</html>

2.2.3 JSX实战之React Native
前面提到过,React Native是ReactJS思想在Native上的实现,也是通过组件化来构建应用,而且组件的生命周期和ReactJs中的生命周期完全一样,不同的是,React Native中没有DOM的概念,只有组件的概念,所以我们在ReactJs中使用的HTML标签以及对DOM的操作在这里是用不了的,但是JSX的语法、事件绑定、自定义属性等这些特性,在React Native和ReactJS中是一样的,下面我们看看如何在React Native中实现上面的MarginBox容器,index.ios.js,相关的JavaScipt代码如下:

var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;
var BoxStyles = StyleSheet.create({
"height50": {
height: 50,
},
"height400": {
height: 400,
},
"height300": {
height: 300,
},
"height200": {
height: 200,
},
"height100": {
height: 100,
},
"width400": {
width: 400,
},
"width300": {
width: 300,
},
"width200": {
width: 200,
},
"width100": {
width: 100,
},
"bgred": {
backgroundColor: "#6AC5AC",
},
"bggreen": {
backgroundColor: "#414142",
},
"bgyellow": {
backgroundColor: "#D64078",
},
"box": {
flexDirection: "column",
flex: 1,
position: "relative",
},
"label": {
top: 0,
left: 0,
paddingTop: 0,
paddingRight: 3,
paddingBottom: 3,
paddingLeft: 0,
position: "absolute",
backgroundColor: "#FDC72F",
},
"top": {
justifyContent: "center",
alignItems: "center",
},
"bottom": {
justifyContent: "center",
alignItems: "center",
},
"right": {
width: 50,
justifyContent: "space-around",
alignItems: "center",
},
"left": {
width: 50,
justifyContent: "space-around",
alignItems: "center",
},
"heightdashed": {
bottom: 0,
top: 0,
right: 20,
borderLeftWidth: 1,
position: "absolute",
borderLeftColor: "#FDC72F"
},
"widthdashed": {
bottom: 25,
left: 0,
right: 0,
borderTopWidth: 1,
position: "absolute",
borderTopColor: "#FDC72F"
},
"yellow": {
color: "#FDC72F",
fontWeight:"900",
},
"white": {
color: "white",
fontWeight:"900",
},

"margginBox":{
"position": "absolute",
"top": 100,
"paddingLeft":7,
"paddingRight":7,
},
"borderBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"paddingBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"elementBox":{
flex: 1,
justifyContent: "space-between",
flexDirection: "row",
},
"measureBox":{
flex: 1,
flexDirection: "row",
justifyContent: "flex-end",
alignItems:"flex-end"
}
})
var Box = React.createClass({
render:function(){
return (
<View style={[BoxStyles.box,BoxStyles[this.props.width],BoxStyles[this.props.height]]}>
<View style={[BoxStyles.top,BoxStyles.height50,BoxStyles[this.props.classBg]]}><Text>top</Text></View>
<View style={[BoxStyles[this.props.childName]]}>
<View style={[BoxStyles.left,BoxStyles[this.props.classBg]]}><Text>left</Text></View>
{this.props.children}
<View style={[BoxStyles.right,BoxStyles[this.props.classBg]]}><Text>right</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50,BoxStyles[this.props.classBg]]}><Text>bottom</Text></View>
<View style={[BoxStyles.label]}><Text>{this.props.boxName}</Text></View>
</View>
)
}
})
var MargginBox = React.createClass({
render:function(){
return (
<View style={[BoxStyles.margginBox]}>
<Box childName="borderBox" height="height400" width="width400" boxName="margin" classBg="bgred">{this.props.children}</Box>
</View>
)
}
})
var BorderBox = React.createClass({
render:function(){
return (
<Box childName="paddingBox" height="height300" width="width300" boxName="border" classBg="bggreen" >{this.props.children}</Box>
)
}
})
var PaddingBox = React.createClass({
render:function(){
return (
<Box childName="elementBox" height="height200" width="width200" boxName="padding" classBg="bgyellow" >{this.props.children}</Box>
)
}
})
var ElementBox = React.createClass({
render:function(){
return (
<View style={[BoxStyles.box,BoxStyles.height100]}>
<View style={[BoxStyles.measureBox]}>
<View style={[BoxStyles.right]}><Text>height</Text></View>
</View>
<View style={[BoxStyles.bottom,BoxStyles.height50]} ><Text>width</Text></View>
<View style={[BoxStyles.label]}><Text>element</Text></View>
<View style={[BoxStyles.widthdashed]}></View>
<View style={[BoxStyles.heightdashed]}></View>
</View>
)
}
})
var BoxContainer = React.createClass({
render:function(){
return (
<MargginBox>
<BorderBox>
<PaddingBox>
<ElementBox>
</ElementBox>
</PaddingBox>
</BorderBox>
</MargginBox>
)
}
})
AppRegistry.registerComponent('Box', () => BoxContainer);

下面我们来分析一下上面的代码:

  • 通过require导入react-native类库,并赋值给React变量。
  • 从React变量导出我们需要的变量,如AppRegistry(用于注册组件)、StyleSheet(用于创建样式)、Text(文本组件,显示文字时使用)、View(视图组件,相当于HTML中的div)等。
  • 通过StyleSheet.create方式创建BoxStyle样式实例,创建的时候,需要我们把事先定义好的javascript对象传入,在这个javascript对象中实现我们对样式的定义。
  • 通过React.createClass的方式定义组件类,这里我们定义了Box、MarginBox和BoxContainer这3个组件.

2.3 React Native开发向导
这里以BoxApp为主线,整体了解和学习一下构建应用的全过程。

2.3.1 配置文件
这里是基于ios上来创建BoxApp应用
首先安装React Native工具。
npm install -g react-native-cli
在开发目录下创建项目
react-native init Box
创建好过后会有很多文件,下面我们分析主要是这两个文件AppDelegate.m和index.ios.js文件

  • AppDelegate.m。这是应用程序入口文件中被调用到的文件,打开文件会看到下面的代码
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"]

在应用启动运行的时候,会自动摘取这bundle文件,该文件里存放的是应用的全部逻辑代码,我们并没有找到这个文件,事实上这个地址只是一个请求地址,而非真正的静态资源文件地址,那么这个地址返回的内容是从哪里来,后面继续学习。

  • index.ios.js 这介开发人员编写代码的入口,项目中涉及的业务组件的定义组件之间的嵌套都会在这里面体现,打开文件下面我们分析这些代码。
/**
* Sample React Native App
* https://github.com/facebook/react-native
*/

'use strict';

var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
} = React;

var MyProject = React.createClass({
render: function() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>
Welcome to React Native!
</Text>
<Text style={styles.instructions}>
To get started, edit index.ios.js
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu
</Text>
</View>
);
}
});

var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
instructions: {
textAlign: 'center',
color: '#333333',
marginBottom: 5,
},
});

AppRegistry.registerComponent('MyProject', () => MyProject);

代码大体结构如下:

  1. 引入React Native包,并导出需要用到的变量1-2行
  2. 创建App需要的样式类styles,相关代码见3-4行
  3. 创建App的逻辑组件Box,并使用样式类styles中的样式,相关代码见5-6行
    1. 最后 将APP渲染到容器中

下面我们装饰2.2的代码直接复制到index.ios.js文件中直接运行

2.2.3 运行
5、启动模拟器,修改端口

  • 包服务默认的启动端口为8081,如果与现有的服务器口有冲突,可以改端口在下面的地方改
    Box/node_modules/react-native/packager/packager.js中打到8081改

  • 改了端口过后改Box/ios/Box/AppDelegate.m改里面的8081

  • 还需要改webSocket监听的端口在文件的Box/node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m中修改initWithUrl

2.3.3 调试
在模拟器上按command+D,会弹出菜单,点击debug in chrome会打开网址进行调试,

  • show FPS Montior,该功能是用来对UI和javascript的FPS的监控,
  • inspect Element,是用来查找元素功能
  • profiling 该功能主要是用来监控应用在一段时间内的指标信息,会生成json文件,需要安装google trace-viewer插件,
  • 调用还有一个工具就是chrome插件,react-developer-tools,安装地址chrome插件上搜索,安装成功过后会出现react标签

2.3.4内部发布