最近突然对react-native感兴趣. 主要被它在iOS和安卓平台通用性吸引, 就花了几天的课余时间学习了一下. 也稍微有点小收获, 想跟大家分享一下. 这门技术在2015年也是火的可以, facebook推出的, 声称是 learn once, write anywhere(感觉就跟java一样, 一次书写,到处运行).hhhh, 我也比较捣鼓新技术, 加上之前开发过iOS, 有点移动端开发基础,后台也熟悉, 所以感觉学起来还算是轻松.
. 具体的环境配置就就不跟大家讲, 网上的教程还挺多, 也很详细.
如.
react-native init DemoRN
npm install --save react-navigation
react-native run-ios
等等.
. 跟大家分享是以下一些知识点:(涉及到内容不多, 后续继续补充哈)
- es6中export和import的介绍.
- 以及一些基础的(props, state的区别)
- es6中fetch进行网络请求的简单介绍.
- react-navigation, 这里主要介绍StackNavigator和TabNavigator,类似iOS中UINavigationController和TabBarController.
- 正向传值和逆向回调传值
- ListView的使用(类似iOS中UITableView,不过还是有点区别)
- 如何书写一些公共模块(将一些常用的功能抽取到一个Util类中)
- 以及一些全局的常量如何归类.
- 关于style样式.
- 生命周期函数
按照惯例啦----先看效果图.
(本来已经录好了gif给大家看的, 发现上传到简书失败,估计后台有文件大小限制, 也尝试了压缩gif, 可是文件还是有点大, 就只能截图给大家看了,不开心啊), 大家将就点吧.
1. es6中的import和export的简单介绍.
Home.js文件
这里是导出默认的模块. Home,
注意一个js文件中只能有一个默认的导出的模块.
export default class Home extends Component {
}
index.ios.js文件
注意, 这样在使用import的时候,是可以自定义导入的默认模块的名字的
import Home from './Home';
可能你在一些文件中会看到这样的导入方式:
import React, {Component} from 'react';
这里我解释下哈
React模块是react.js文件默认导出的文件.
{Component}注意这里加了大括号, 表示react.js文件中非默认导出
(即没有default关键修饰导出的模块), 还有注意一点的是
非默认模块在import的时候是不可以重命名的.
2. 关于props和state的简单介绍.
RN的组件其实就是一个状态机, 主要的两个参数就是props和state,
最后返回一个虚拟DOM, 进行渲染.(这也是它的高效原因之一).
props 一般用于父组件向子组件通信,在组件之间进行传值使用.
state 一般用于组件内部的状态维护, 跟新组件内部数据, 状态, 重新进行虚拟DOM的渲染.
注意:
1. 不管是props还是state的改变, 都会引发render函数的重新调用.
2. 都可以由组件自身提供的函数进行初始化.
3. props是一个父组件传递给子组件的数据流 getDefaultProps
4. state只能在自身组件中setState getInitalState
5. getDefaultProps和getInitalState在es6中推荐用constructor进行初始化.
如:
constructor(props) {
super(props);
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
isLoaded: false,
dataSource: ds
}
}
3.fetch进行网络请求的简单介绍.
一个最简单的请求就是这样:
fetch(url).then((response) => {
return response.json();
}).then((responseData) => {
callBack(responseData[objectName]);
}).catch((error) => {
alert(error);
})
当然这里你也可以指定请求方式, 请求头, 以及请求参数, (由于示例,未详细介绍, 具体还请读者自行去查哈).
4 StackNavigator的使用.
注意要导入
import {StackNavigator, TabNavigator} from 'react-navigation';
StackNavigator是facebook最近才推出的react-navigation框架中所带的一个模块, 超级好用, 比之前的那些navigatorIOS好用多了. gitHub上的star也猛增.
示例:
const Nav2 = StackNavigator(
{
personCenter: {screen: PersonCenter},
movieList:{screen:MovieList},
},
{
navigationOptions:{
headerStyle:{
backgroundColor:"#eec",
}
}
}
);
import PersonCenter from './MyApp/PersonCenterModule/PersonCenter';
import MovieList from './MyApp/PersonCenterModule/MovieList';
这里PersonCenter和MovieList是导入的另外两个模块, 前面的名称是可以自定义的.
navigationOptions的就是全局的导航栏的设置.(会影响每一个导航栏). 当然也可以在
每个页面进行单页面自定义.
如:
export default class MovieList extends Component {
static navigationOptions = {
tabBarVisible: false,
title: "科技新闻"
}
}
讲导航栏肯定少不了页面跳转.
导航栏提供了一些函数和属性.这里介绍常用的.
this.props.navigation.navigate('需要跳转到的页面', {参数传递, 回调函数的定义})
this.props.navigation.goBack()返回上一级
this.props.navigation.state.params 获取传递参数的值.
或许读者会对这样的写法有疑问:
const {params} = this.props.navigation.state.params, 我解释下哈
这样是相当于等价先判断this.props.navigation.state中是否有params这个属性,
如何没有程序运行时会由警告.
如:
跳转至homeSecond页面,并且将传递titleValue值. 这里homeSecond是在导航控制器
{screen: PersonCenter}
这里指定的.
<Button title="详情" onPress={() => {
const {navigate} = navigation;
navigate('homeSecond', {titleValue: "哈哈"})
}}/>
5 正向传值和逆向回调传值
先看代码咯:
export default class HomeSecond extends Component {
static navigationOptions = {
title: "HomeSecond",
tabBarVisible:false
}
constructor(props) {
super(props);
const {params} = props.navigation.state;
this.state = {
titleValue: params.titleValue
}
}
render() {
const {navigate} = this.props.navigation;
return (
<View style={styles.container}>
<Text style={styles.text}>{this.state.titleValue}</Text>
<Button title="继续点击"
onPress={() => navigate('homeThird',
{
titleValue: this.state.titleValue,
username: "React-Native",
callBack: (data) => {
this.setState({
titleValue: data
});
}
})
}/>
</View>
);
}
}
这里首先初始化state, 有一个属性为titleValue, 这里是作为接收下级界面回调传回的值.
navigate('homeThird',{
titleValue: this.state.titleValue,
username: "React-Native",
callBack: (data) => {
this.setState({
titleValue: data
});
}
由于该界面是在导航控制器(StackNavigator)的管理下,
所以该界面的this.props会 自动有一个navigatioin参数,
那么就可以使用这个navigation中的navigate进行界 面跳转和参数传递了啊.
const {navigate} = this.props.navigation;
利用该参数先进行跳转到homeThird.js页面. 并且传递titleValue和username的值,
以及一个callback的回调函数.
下面看homeThird.js页面如何接收的.
这里接收titleValue和username.
constructor(props) {
super(props);
this.state = {
textInputValue: props.navigation.state.params.titleValue,
username:props.navigation.state.params.username
}
}
render() {
const {params} = this.props.navigation.state;
return (
<View style={styles.container}>
<Text style={styles.text}>{params.username}</Text>
<TextInput style={styles.textInputViewStyle}
placeholder="请输入"
onChangeText={(text) => this.setState({textInputValue: text})}/>
<Button title="确认并返回"
onPress={this.clickBackBtn.bind(this)}/>
</View>
);
}
clickBackBtn() {
const {goBack} = this.props.navigation;
const {params} = this.props.navigation.state;
params.callBack(this.state.textInputValue);
goBack();
}
这里先获取到前一个界面传递过来的参数params,
得到回调函数callBack进行回调传值. 将输入框中的值逆传给上一个界面.
6. TabNavigator的简单使用
注意要导入
import {StackNavigator, TabNavigator} from 'react-navigation';
和StackNavigator非常相似.
const HelloRN = TabNavigator(
{
first: {
screen: Nav1,
navigationOptions: {
tabBarLabel: '主页',
tabBarIcon: ({tintColor}) => (
<Image style={{tintColor: tintColor}} source={require('./MyApp/images/tab_groups@2x.png')}/>)
},
},
second: {
screen: Nav2,
navigationOptions: {
tabBarLabel: "我的",
tabBarIcon: ({tintColor}) => (
<Image style={{tintColor: tintColor}} source={require('./MyApp/images/tab_settings@2x.png')}/>)
}
},
},
//这里设tabbar的一些全局属性, 会影响所有的页面中的tabbar.
{
animationEnabled: false, // 切换页面时是否有动画效果
tabBarPosition: 'bottom', // 显示在底端,android 默认是显示在页面顶端的
swipeEnabled: false, // 是否可以左右滑动切换tab
backBehavior: 'none', // 按 back 键是否跳转到第一个Tab(首页), none 为不跳转
tabBarOptions: {
activeTintColor: '#17e', // 文字和图片选中颜色
inactiveTintColor: '#666', // 文字和图片未选中颜色
showIcon: true, // android 默认不显示 icon, 需要设置为 true 才会显示
indicatorStyle: {
height: 0 // 如TabBar下面显示有一条线,可以设高度为0后隐藏
},
style: {
backgroundColor: '#eee', // TabBar 背景色
height: 44, //默认为44
},
labelStyle: {
fontSize: 14, // 文字大小
},
},
}
);
7 ListView的使用
//创建一个DataSource数据源.
constructor(props) {
super(props);
//这里进行DataSource的创建, 指定渲染策略.
let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
isLoaded: false,
dataSource: ds
}
}
//进行数据请求. 获取数据,更新state 进而重新渲染页面,
//注意只要state中的值发生变化就会进行render方法的调用.
componentDidMount() {
Util.getRquest(Constants.IMOOC_API, (data) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(data),
isLoaded: true
});
}, "data");
}
页面渲染
render() {
if (!this.state.isLoaded) {
return this.renderLoadingView();
}
return (
<View style={styles.container}>
<ListView
style={styles.listView}
dataSource={this.state.dataSource}
renderRow={this._renderRow.bind(this)}
initialListSize={10}/>
</View>
);
}
渲染每一行
_renderRow(model) {
return (
<View style={styles.rowContainer}>
<Image source={{uri: model.picSmall}} style={styles.cellImage}/>
<View style={styles.textContainer}>
<Text style={styles.title}>{model.name}</Text>
<Text style={styles.subTitle}>{model.description}</Text>
</View>
</View>
)
}
//加载等待的view
renderLoadingView() {
return (
<View style={{flex: 1, alignItems: "center", justifyContent: "center"}}>
<Text style={{fontSize: 18, color: "#17e"}}>
加载中...
</Text>
</View>
);
}
8 公共模块和全局常量的书写.
Constants.js文件
/**
*定义APP需要要的全局常量文件.
* 存放全局的const, 如:公共的API, 以及主题等.
*/
const Constatnts = {
/**
* 新闻接口API
*/
NEWS_API : 'http://c.m.163.com/nc/article/list/T1348649580692/0-20.html',
/**
* 慕课网API
*/
IMOOC_API:"http://www.imooc.com/api/teacher?type=4&num=30"
};
export default Constatnts;
MyUtils文件如下. 常用的工具如设备屏幕的宽高, 设备的操作系统.以及get请求方法的封装.
const Dimensions = require('Dimensions');
const Platform = require('Platform');
export default class MyUtils {
static getScreenWidth() {
return Dimensions.get('window').width;
}
static getScreenHeight() {
return Dimensions.get('window').height;
}
static getPlatformOS() {
return Platform.OS;
}
static getRquest(url, callBack, objectName) {
fetch(url).then((response) => {
return response.json();
}).then((responseData) => {
callBack(responseData[objectName]);
}).catch((error) => {
alert(error);
})
}
}
9 关于style样式的简单介绍
你可以内联这样写, 注意这里要加两个大括号, 外层大括号是javascript的语法. 内层大括号是jsx的语法.
<View style={{flex:1,alignItems:"center", justifyContent:"center"}}>
<Text style={{ fontSize:18, color:"#17e"}}>
加载中...
</Text>
</View>
当然, 更推荐这样的方式(外联).
const styles = StyleSheet.create({
ListView: {
marginTop: 20,
backgroundColor: "#F5FCFF"
},
rowContainer: {
flexDirection: "row",
flex: 1,
paddingTop: 5,
paddingBottom: 5,
borderBottomWidth: 1,
borderColor: "#666"
},
image: {
width: 120,
height: 100,
marginLeft: 10
},
textContainer: {
flex: 1,
paddingLeft: 10,
paddingRight: 10,
justifyContent: "space-around"
},
title: {
color: "black",
fontSize: 15
},
subtitle: {
color: "#666",
fontSize: 13,
textAlign: "right",
}
});
/**
* justifyContent是垂直方式
* alignItems是水平方式
*
* 具体的样式有:
* 1. center 容器内居中对齐
* 2. flex-start 从容器的头部开始排列
* 3. flex-end 从容器的底部开始排列
* 4. space-around 容器内各组件以及与容器之间间距相等
* 5. space-between 容器内各组之间间距相等(不包含和容器之间)
*/
总结
好了, 今天就介绍到这里了, 一些常用的简单功能基本上都讲了哈. 可能由于我的水平有限, 讲的不是很清楚, 希望读者谅解. 待我再学些时日, 再来向大家献丑. hhhh(腹黑). 谢谢!
网友评论