2.1 flexbox布局
flexbox是React Native应用开发不可少的内容
2.1.2 布局模型
flexbox布局由伸缩容器和伸缩项目组成。任何一个元素都可以指定为flexbox布局,其中设为display:flex或display:inline-flex的元素称为伸缩容器,伸缩容器的子元素称为伸缩项目,伸缩项目使用伸缩布局模型来排版
上面图片引用网址: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 伸缩容器属性
支持的属性有:
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 伸缩项目属性还有以下几种:
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的如下属性:
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
我们用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代码涉及的属性如下:
align-items
React Native中涉及的属性如下:
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中的显示层级是后面比前面的高
书写格式的差异:
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组件,下面来解释一下:
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");
}
})
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开发的应用就比较清晰了
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);
下面我们来分析一下上面的代码:
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文件
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle"]
在应用启动运行的时候,会自动摘取这bundle文件,该文件里存放的是应用的全部逻辑代码,我们并没有找到这个文件,事实上这个地址只是一个请求地址,而非真正的静态资源文件地址,那么这个地址返回的内容是从哪里来,后面继续学习。
/** * 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);
代码大体结构如下:
下面我们装饰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
2.3.3 调试
在模拟器上按command+D,会弹出菜单,点击debug in chrome会打开网址进行调试,
2.3.4内部发布
略