1.AppRegistry
/*
AppRegistry负责注册运行React Native应用程序的入口。通过AppRegistry.registerComponent来注册,当注册完成后,
Native系统(Objective-C)就会加载jsbundle文件并且触发AppRegistry.runApplication运行应用。有以下方法:
1.registerConfig(config: Array<AppConfig>):静态方法,注册配置。
2.registerComponent(appKey: string, getComponentFunc: ComponentProvider):注册入口组件。
3.registerRunnable(appKey: string, func: Function):注册函数监听。
4.getAppKeys():获取registerRunnable注册的监听键。
5.runApplication(appKey: string, appParameters: any):运行App。
*/
启动应用时,x-code日志输出如下:
2016-05-19 13:48:28.777 [info][tid:com.facebook.react.JavaScript] Running application
"InformationServicesRN" with appParams: {"rootTag":1,"initialProps":{}}.
__DEV__ === true, development-level warning are ON,
performance optimizations are OFF
其实,上面的日志是由runApplication打印出来的,添加如下代码:
alert(AppRegistry.runApplication);
AppRegistry.registerComponent('InformationServicesRN', () => app);
效果图如下:
runApplication函数中的console.log()打印的正是我们启动时的日志。
也可以使用registerRunnable注册一些AppKey:
AppRegistry.registerRunnable('vczero', function(){
console.log('vczero');
});
AppRegistry.registerRunnable('react-native', function(){
console.log('react-native');
});
alert(AppRegistry.getAppKeys());
效果如下:
2.AsyncStorage
/*
AsyncStorage是一个简单的、具有异步特性的键值对的存储系统。相对整个App而言,它是全局的,应该用于替代LocalStorage。
AsyncStorage提供了比较安全的方法供我们使用。每个方法都有一个回调函数,而回调函数的第一个参数都是错误对象。如果发生错误该对象就会展示错误信息,否则为null。所有的方法执行后,都会返回一个Promise对象。具体的方法如下所示:
1.static getItem(key: string, callback:(error, result)): 根据键来获取值,获取的结果会在回调函数中。
2.static setItem(key: string, value: string, callback:(error)):设置键值对。
3.static removeItem(key: string, callback:(error)):根据键移除一项。
4.static mergeItem(key: string, value: string, callback:(error)):合并现有值和输入值。
5.static clear(callback:(error)):清除所有的项目。
6.static getAllKeys(callback:(error)):获取所有的键。
7.static multiGet(keys, callback:(error, result)):获取多项,其中keys是字符串数组。
8.static multiSet(keyValuePairs, callback:(error)):设置多项,其中keyValuePairs是字符串的二维数组。
9.static multiRemove(keys, callback:(error)):删除多项,其中keys是字符串数组。
10.static multiMerge(keyValuePairs, callback:(error)):多个键值对合并,其中keyValuePairs是字符串的二维数组。
*/
以购物车为例,来看看效果:
2.1 数据模型构建
这里以购买水果为例定义一个静态的商品数组。
var Model = [
{
id: '1',
title: '佳沛新西兰进口猕猴桃',
desc: '12个装',
price: 99,
url: 'http://vczero.github.io/ctrip/guo_1.jpg'
},
{
id:'2',
title: '墨西哥进口牛油果',
desc: '6个装',
price: 59,
url: 'http://vczero.github.io/ctrip/guo_2.jpg'
},
{
id:'3',
title: '美国加州进口车厘子',
desc: '1000g',
price: 91.5,
url: 'http://vczero.github.io/ctrip/guo_3.jpg'
},
{
id:'4',
title: '新疆特产西梅',
desc: '1000g',
price: 69,
url: 'http://vczero.github.io/ctrip/guo_4.jpg'
},
{
id:'5',
title: '陕西大荔冬枣',
desc: '2000g',
price: 59.9,
url: 'http://vczero.github.io/ctrip/guo_5.jpg'
},
{
id:'6',
title: '南非红心西柚',
desc: '2500g',
price: 29.9,
url: 'http://vczero.github.io/ctrip/guo_6.jpg'
}
];
2.2 列表项组件
用于渲染商品的图片和名称
//TouchableOpacity:透明触摸。用户点击时,点击的组件会出现透明效果。
//resizeMode="contain" : 图片缩放模型,"contain"自适应所在容器模式
//这里press点击事件、url、title都由父组件List传递过来
var Item = React.createClass({
render: function(){
return(
<View style={styles.item}>
<TouchableOpacity onPress={this.props.press}>
<Image
resizeMode="contain"
style={styles.img}
source={{uri:this.props.url}}>
<Text numberOfLines={1} style={styles.item_text}>{this.props.title}</Text>
</Image>
</TouchableOpacity>
</View>
);
}
});
2.3 列表组件
var List = React.createClass({
getInitialState: function(){
return{
count:0
};
},
//在组件第一次绘制之后,会调用 componentDidMount() ,通知组件已经加载完成。
componentDidMount: function(){
var _that = this;
AsyncStorage.getAllKeys(function(err, keys){
if(err){
//TODO:存储取数据出错
}
//将存储的商品条数反应到按钮上
_that.setState({
count: keys.length
});
});
},
render: function() {
var list = [];
for(var i in Model){
if(i % 2 === 0){
var row = (
<View style={styles.row}>
<Item url={Model[i].url}
title={Model[i].title}
press={this.press.bind(this, Model[i])}></Item>
<Item
url={Model[parseInt(i)+1].url}
title={Model[parseInt(i)+1].title}
press={this.press.bind(this, Model[parseInt(i)+1])}></Item>
</View>);
list.push(row); //类似OC的数组addObject
}
}
var count = this.state.count;
var str = null;
if(count){
str = ',共'+ count + '件商品';
}
return (
<ScrollView style={{marginTop:10}}>
{list}
<Text onPress={this.goGouWu} style={styles.btn}>去结算{str}</Text>
</ScrollView>
);
},
goGouWu: function(){
this.props.navigator.push({
component: GouWu,
title:'购物车'
});
},
press:function(data){
var count = this.state.count;
count ++;
//改变数字状态
this.setState({
count: count
});
//AsyncStorage存储
AsyncStorage.setItem('SP-' + this.genId() + '-SP', JSON.stringify(data), function(err){
if(err){
//TODO:存储出错
}
});
},
//生成随机ID:GUID
genId:function(){
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
}).toUpperCase();
}
});
2.4 购物车组件
购物车页面
var GouWu = React.createClass({
getInitialState: function(){
return {
data: [],
price: 0
};
},
render: function(){
var data = this.state.data;
var price = this.state.price;
var list = [];
for(var i in data){
price += parseFloat(data[i].price);
list.push(
<View style={[styles.row, styles.list_item]}>
<Text style={styles.list_item_desc}>
{data[i].title}
{data[i].desc}
</Text>
<Text style={styles.list_item_price}>¥{data[i].price}</Text>
</View>
);
}
var str = null;
if(price){
str = ',共' + price.toFixed(1) + '元';
}
return(
<ScrollView style={{marginTop:10}}>
{list}
<Text style={styles.btn}>支付{str}</Text>
<Text style={styles.clear} onPress={this.clearStorage}>清空购物车</Text>
</ScrollView>
);
},
componentDidMount: function(){
var _that = this;
AsyncStorage.getAllKeys(function(err, keys){
if(err){
//TODO:存储取数据出错
//如果发生错误,这里直接返回(return)防止进入下面的逻辑
}
AsyncStorage.multiGet(keys, function(errs, result){
//TODO:错误处理
//得到的结果是二维数组
//result[i][0]表示我们存储的键,result[i][1]表示我们存储的值
var arr = [];
for(var i in result){
arr.push(JSON.parse(result[i][1]));
}
_that.setState({
data: arr
});
});
});
},
clearStorage: function(){
var _that = this;
AsyncStorage.clear(function(err){
if(!err){
_that.setState({
data:[],
price: 0
});
alert('购物车已经清空');
}
//TODO:ERR
});
}
});
2.5 完整的功能
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
Image,
NavigatorIOS,
ScrollView,
AsyncStorage,
TouchableOpacity,
} = React;
var Model = [...];
var Item = React.createClass({...});
var List = React.createClass({...});
var GouWu = React.createClass({...});
var App = React.createClass({
render: function() {
return (
<NavigatorIOS
style={styles.container}
initialRoute={
{
component: List,
title: '水果列表'
}
}/>
);
}
});
var styles = StyleSheet.create({
container: {
flex: 1,
},
row:{
flexDirection: 'row',
marginBottom: 10,
},
item:{
flex:1,
marginLeft:5,
borderWidth:1,
borderColor:'#ddd',
marginRight:5,
height:100,
},
img:{
flex:1,
backgroundColor: 'transparent'
},
item_text:{
backgroundColor: '#000',
opacity: 0.7,
color:'#fff',
height:25,
lineHeight:18,
textAlign:'center',
marginTop:74
},
btn:{
backgroundColor:'#FF7200',
height:33,
textAlign:'center',
color:'#fff',
marginLeft:10,
marginRight:10,
lineHeight:24,
marginTop:40,
fontSize:18,
},
list_item:{
marginLeft:5,
marginRight:5,
padding:5,
borderWidth:1,
height:30,
borderRadius:3,
borderColor:'#ddd'
},
list_item_desc:{
flex:2,
fontSize:15
},
list_item_price:{
flex:1,
textAlign:'right',
fontSize:15
},
clear:{
marginTop:10,
backgroundColor:'#FFF',
color:'#000',
borderWidth:1,
borderColor:'#ddd',
marginLeft:10,
marginRight:10,
lineHeight:24,
height:33,
fontSize:18,
textAlign:'center',
}
});
AppRegistry.registerComponent('App', () => App);
效果如下: