react-native学习
第一章
- 启动页
1.进入启动页后,3S后进入main主页
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View,Image} from 'react-native'; type Props = {}; import Main from './Main'; export default class StartImage extends Component<Props> { componentDidMount(){ setTimeout(()=>{this.props.navigator.replace({//替换路由 component:Main, })},3000) } render() { return ( <View style={styles.container}> <Image source={{uri:'startmage'}} style={styles.ImageStartStyle}/> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1 }, ImageStartStyle:{ flex:1 } });
2. TabNavigator底部导航
export default class Main extends Component<Props> { constructor(props){ super(props); this.state={ selectedTab:'home' } } render(){ return ( <TabNavigator> {/*--首页--*/} {this.renderTabBarItem('首页','icon_tabbar_homepage','icon_tabbar_homepage_selected','home','首页',Home)} {/*--商家--*/} {this.renderTabBarItem('商家','icon_tabbar_merchant_normal','icon_tabbar_merchant_selected','store','商家',Store)} {/*--我的--*/} {this.renderTabBarItem('我的','icon_tabbar_mine','icon_tabbar_mine_selected','mine','我的',Mine)} {/*--更多--*/} {this.renderTabBarItem('更多','icon_tabbar_misc','icon_tabbar_misc_selected','more','更多',More)} </TabNavigator> ); } //tabNavigator的封装 renderTabBarItem(title,iconName,SelectedIconName,selectedTab,componentName,component){ return ( <TabNavigator.Item title={title} titleStyle={styles.tabText} selectedTitleStyle={styles.selectedTabText} renderIcon={()=><Image source={{uri:iconName}} style={styles.iconStyle}/>} renderSelectedIcon={()=><Image source={{uri:SelectedIconName}} style={styles.iconStyle}/>} onPress={()=>{this.setState({selectedTab:selectedTab})}} selected={this.state.selectedTab===selectedTab} > <Navigator initialRoute={{name:componentName,component:component}} configureScene={()=>{ return Navigator.SceneConfigs.PushFromRight; }} renderScene={(route,navigator)=> <route.component navigator={navigator} {...route.passProps}/>} /> </TabNavigator.Item> ) } }
3. ListView的使用
export default class TopListView extends Component<Props> { static defaultProps = { dataArr:[] }; constructor(props){ super(props); this.state={ datas:new ListView.DataSource({ rowHasChanged:((row1,row2)=>row1!==row2) }) } this.onLoad(); } pushToDetail(){ this.props.navigator.push( { component:HomeDetail,//要跳转的板块 title:'详情页' } ) } onLoad(){ var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2}); setTimeout(()=>{this.setState({ datas:ds.cloneWithRows(this.props.dataArr) }) },2000) } //具体的cell renderRow(rowdata){ return( <TouchableOpacity onPress={()=>{this.pushToDetail()}}> <View style={styles.cellStyle}> <Image source={{uri:rowdata.image}} style={{width:52,height:52}}/> <Text>{rowdata.title}</Text> </View> </TouchableOpacity> ) } render() { return ( <ListView dataSource={this.state.datas} renderRow={this.renderRow} contentContainerStyle={styles.contentViewStyle} scrollEnabled={false} /> ); } }
- 自己构建组件后,要传相应的属性值
组件构成如下:
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View,Image,TouchableOpacity} from 'react-native'; type Props = {}; var Dimensions=require('Dimensions'); var {width}=Dimensions.get('window'); export default class MiddleView extends Component<Props> { static defaultProps={ title:'', subTitle:'', rightIcon:'', titleColor:'' } render() { return ( <TouchableOpacity onPress={()=>{alert("点击了")}}> <View style={styles.container}> {/*左边*/} <View> <Text style={[{color:this.props.titleColor},styles.titleStyle]}>{this.props.title}</Text> <Text style={styles.subTitleStyle}>{this.props.subTitle}</Text> </View> <Image source={{uri:this.props.rightIcon}} style={{width:64,height:43}}/> </View> </TouchableOpacity> ); } } const styles = StyleSheet.create({ container: { backgroundColor:'white', width:width*0.5-1, height:59, marginBottom:1, marginRight:1, flexDirection:'row', alignItems:'center', justifyContent:'space-around' }, titleStyle:{ fontSize:18, fontWeight:'bold' }, subTitleStyle:{ color:'gray', } });
使用组件如下:
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View,Image,TouchableOpacity} from 'react-native'; import MiddleView from './MiddleCommentView'; type Props = {}; var TopMiddleData=require("./middleView.json"); var Dimensions=require('Dimensions'); var {width}=Dimensions.get('window'); export default class HomeMiddleView extends Component<Props> { renderLeftView(){ var data=TopMiddleData.dataLeft[0]; return( <TouchableOpacity onPress={()=>{alert("111")}}> <View style={styles.leftViewStyle}> <Image source={{uri:data.img1}} style={styles.leftImageStyle}/> <Image source={{uri:data.img2}} style={styles.leftImageStyle}/> <Text style={{color:'gray'}}>{data.title}</Text> <View style={{flexDirection:'row',marginTop:5}}> <Text style={{color:'blue',marginRight:5}}>{data.price}</Text> <Text style={{color:'orange',backgroundColor:'yellow'}}>{data.sale}</Text> </View> </View> </TouchableOpacity> ) } renderRightView(){ var itemArr=[]; var rightData=TopMiddleData.dataRight; for(var i=0;i<rightData.length;i++) { var data=rightData[i]; itemArr.push( <MiddleView key={i} title={data.title} subTitle={data.subTitle} rightIcon={data.rightImage} titleColor={data.titleColor} /> ) } return itemArr; } render() { return( <View style={styles.container}> {this.renderLeftView()} <View> {this.renderRightView()} </View> </View> ) } } const styles = StyleSheet.create({ container: { marginTop:15, flexDirection:'row' }, leftViewStyle:{ width:width*0.5, height:119, backgroundColor:'white', marginRight:1, alignItems:'center', justifyContent:'center' }, leftImageStyle:{ width:120, height:30, resizeMode:'contain' } })
5. 通过Navigator进行传参
注意如果父组件里面有子组件,点击子组件进行页面跳转,传参数只能子组件一个一个往上传到父组件(回调函数),ShopCenterItem==>ShopCenter,为什么呢?因为navigator只到父组件,如果说直接子组件进行页面跳转,肯定是跳转不过去,会报错,所以只能一层一层的往上传。
代码 如下 ShopCenter.js:
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View,TouchableOpacity,ScrollView,Image} from 'react-native'; type Props = {}; import BottomCommentCell from './BottomCommentCell'; var home_D5=require('./home_D5.json'); class ShopCenterItem extends Component{ static defaultProps={ shopImage:'', shopSale:'', shopName:'', detailurl:'', popTopShopCenter:null } render(){ return( <TouchableOpacity onPress={()=>{this.clickItem(this.props.detailurl)}}> <View style={styles.itemViewStyle}> <Image source={{uri:this.props.shopImage}} style={styles.imageStyle}/> <Text style={styles.shopSaleStyle}>{this.props.shopSale}</Text> <Text style={styles.shopNameStyle}>{this.props.shopName}</Text> </View> </TouchableOpacity> ) } clickItem(url){ if(this.props.detailurl==null) return; this.props.popTopShopCenter(url) } } export default class ShopCenter extends Component<Props> { static defaultProps={ popToHomeView:null, } renderAllItem(){ var itemArr=[]; var shopData=home_D5.data; for(var i=0;i<shopData.length;i++) { var data=shopData[i]; itemArr.push( <ShopCenterItem shopImage={data.img} shopSale={data.showtext.text} shopName={data.name} detailurl={data.detailurl} key={i} popTopShopCenter={(url)=>{this.popTopHome(url)}} /> ) } return itemArr; } popTopHome(url){ if(this.props.popToHomeView==null) return; this.props.popToHomeView(url); } render() { return ( <View style={styles.container}> <BottomCommentCell leftIcon='gw' leftTitle='购物中心' rightTitle='全部4家' /> {/*下部分*/} <ScrollView style={styles.scrollViewStyle} horizontal={true}//横向 showsHorizontalScrollIndicator={false} > {this.renderAllItem()} </ScrollView> </View> ); } } const styles = StyleSheet.create({ container: { marginTop:15 }, imageStyle:{ width:120, height:100, borderRadius:8 }, scrollViewStyle:{ flexDirection:'row', backgroundColor:'white', padding:10 }, itemViewStyle:{ margin:8 }, shopSaleStyle:{ position:'absolute', left:0, bottom:30, backgroundColor:'red', color:'white', padding:3, borderTopRightRadius:8, borderBottomRightRadius:8 }, shopNameStyle:{ textAlign:'center', marginTop:5, } });
home.js
import React, {Component} from 'react'; import {Platform, StyleSheet, Text, View,TouchableOpacity,TextInput,Image,ScrollView} from 'react-native'; type Props = {}; import HomeDetail from './homeDetail'; import TopView from './homeTopView'; import HomeMiddleView from './homeMiddleView'; import MiddleBottomView from './MiddleBottomView'; import ShopCenter from './shopCenter'; import {Navigator} from 'react-native-deprecated-custom-components'; var Dimensions=require('Dimensions'); var width=Dimensions.get('window').width; var height=Dimensions.get('window').height; export default class Home extends Component<Props> { constructor(props){ super(props); this.state={ word:'', } } pushToDetail(){ this.props.navigator.push( { component:HomeDetail,//要跳转的板块 title:'详情页', } ) } pushToShopCenterDetail(url){ this.props.navigator.push( { component:HomeDetail,//要跳转的板块 passProps:{ url:url, onCallBack:(word)=>{ this.setState({ word:word }) } } } ) } renderNavBar(){ return( <View style={styles.navBarStyle}> <Text>广州</Text> <TextInput placeholder='输入商家,品类,商圈' style={styles.topInputStyle} /> <View style={styles.rightNavViewStyle}> <Image source={{uri:'icon_homepage_message'}} style={styles.navRightImgStyle}/> <Image source={{uri:'icon_homepage_scan'}} style={styles.navRightImgStyle}/> </View> </View> ) } render() { return ( <View style={styles.container}> {/*首页的导航条*/} {this.renderNavBar()} {/*首页的主要内容*/} <ScrollView> {/*头部的View*/} <TopView/> {/*中间的内容*/} <HomeMiddleView/> {/*中间下半部分的内容*/} <MiddleBottomView/> {/*购物中心*/} <ShopCenter popToHomeView={(url)=>{this.pushToShopCenterDetail(url)}}/> <Text>{this.state.word}</Text> </ScrollView> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, backgroundColor: '#F5FCFF', }, topInputStyle:{ width:width*0.8, height:30, backgroundColor:'white', marginTop:4 }, navRightImgStyle:{ width:30, height:30 }, navBarStyle:{ height:64, backgroundColor:'rgba(255,96,0,1.0)', flexDirection:'row', alignItems:'center', }, rightNavViewStyle:{ flexDirection:'row', height:64, alignItems:'center' } });
1.注意事项
创建组件的时候,组件的首字母一定要大写,不然会报错
ListView
ListView组件是React Native中一个比较核心的组件,用途非常广,设计初衷就是用来高效的展示垂直滚动的列表数据
ListView继承了ScrollView的所有属性
使用步骤:
创建一个ListView.DataSource数据源,然后给它传递一个普通的数组数据
getInitialState(){
//初始化数据源(rowHasChanged是优化的一种手段,只有当r1!==r2的时候才会重新渲染)
var ds=new ListView.DataSource({rowHasChanged:(r1,r2)=>r1!==r2});
return{
dataSource:ds.cloneWithRows(['内容0‘,’内容1‘,’内容2‘,’内容3‘,’内容4‘,’内容5‘])
}
},
render(){
return(
//根据数据源实例化一个ListView
<ListView style={{backgroundColor:‘yellow’}}
//获取数据源
dataSource={this.state.dataSource}
//根据数据源创建一个Item
renderRow={this.renderRow}
/>
)
},
renderRow(rowData,sectionID,rowID){
return(
//实例化Item
<Text style={{backgroundColor:‘red’,height:44}}>
内容{rowData},在第{sectionID}组第{rowID}行
)}
首先,ListView需要数据源,那么我们就先来自定义一下数据源的Json数据
[ {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"}, {"title" : "icon", "img" : "icon"}, {"title" : "lufei", "img" : "lufei"} ]
获取数据
var newData=require(’./Data/localData.json’)
初始化数据源
getInitialState(){ var ds = new ListView.DataSource({rowHasChanged:(r1, r2) => r1 != r2}); return{ // 将获得的数组传递给dataSource dataSource : ds.cloneWithRows(newData) } },
接着就是根据数据源实例化ListView
视图部分
render(){ return( <View style={styles.container}> <ListView dataSource={this.state.dataSource} renderRow={this.renderRow} /> </View> ); }, // 返回一个Item renderRow(rowData){ return( <View style={styles.itemStyle}> <Image source={{uri:rowData.img}} style={styles.imageStyle}/> <View style={styles.subItemStyle}> <Text style={{marginTop:5, fontSize:17}}>{rowData.title}</Text> <Text style={{marginBottom:5, fontSize:13, color:'green'}}>简介</Text> </View> </View> ); }
ListView 九宫格布局实现
从上面可以看出,这个案例是为了实现类似CollectionView效果,通常情况下,ListView是纵向排列的而此案例我们需要它横向排列,那么就需要使用到上面提到的contentContainerStyle属性,向里面添加flexDirection:'row’和flexWrap:'wrap’两个属性
当然了,我们还是需要自定义一组数据供ListView使用,这边就使用上面案例的数据
根据数据实例化ListView,参考上面案例,这里只粘贴Item部分,其它的就不重复了
视图部分
var ListViewDemo = React.createClass({ getInitialState(){ // 初始化数据源 var ds = new ListView.DataSource({rowHasChanged:(r1, r2) => r1 != r2}); return{ dataSource : ds.cloneWithRows(newData) } }, render(){ return( <ListView dataSource={this.state.dataSource} renderRow={this.renderRow} // 设置contentContainerStyle contentContainerStyle={styles.contentViewStyle} /> ); }, // 返回一个Item renderRow(rowData){ return( {/* 实例化Item */} <View style={styles.itemStyle}> <Image source={{uri:rowData.img}} style={styles.itemImageStyle}/> <Text>{rowData.title}</Text> </View> ); } var styles = StyleSheet.create({ contentViewStyle: { // 主轴方向 flexDirection:'row', // 换行 flexWrap:'wrap' }
RN组件的生命周期整理如下图:
组件的属性(props)和状态(state)
1.属性(props)
它是组件的不可变属性(组件自己不可以自己修改props)
组件自身定义了一组props作为对外提供的接口,展示一个组件时只需要指定props作为节点的属性。 一般组件很少需要对外公开方法,唯一的交互途径就是props。所以说它也是父组件与子组件通信的桥梁。
组件自己不可以自己修改props,只可由其他组件调用它时在外部修改。
2.状态(state)
它是组件的内部状态属性,主要用来存储组件自身需要的数据
除了初始化时可能由props来决定,之后就完全由组件自身去维护。
组件中由系统定义了setState方法,每次调用setState时都会更新组件的状态,触发render方法重新渲染界面。
需要注意的是render方法是被异步调用的,这可以保证同步的多个setState方法只会触发一次render,这样做是有利于提高性能的。
组件的生命周期
对于自定义组件,除了必须实现的render方法,还有一些其他的可选方法可被调用。这些方法会在组件的不同时期之行,所以也可以说这些方法是组件的生命周期方法。
注意:由于this.props和this.state都用于描述组件的特性,可能会产生混淆。一个简单的区分方法是,this.props表示那些一旦定义,就不再改变的特性,而this.state是会随着用户互动而产生变化的特性。
1.constructor(props)
这里是对控件的一些状态进行初始化,由于该函数不同于defaultProps,在以后的过程中,会再次调用,所以可以将控制控件的状态的一些变量放在这里初始化,如控件上显示的文字,可以通过this.state来获取值,通过this.setState来修改state值。
2.componentWillMount()
准备加载组件
这个调用时机是在组件创建,并初始化了状态之后,在第一次绘制 render() 之前。可以在这里做一些业务初始化操作,也可以设置组件状态。这个函数在整个生命周期中只被调用一次。
如果在这个函数里面调用setState,本次的render函数可以看到更新后的state,并且只渲染一次。
3.render()
render是一个组件必须有的方法,形式为一个函数,渲染界面,并返回JSX或其他组件来构成DOM,和Andoid的XML布局、WPF的XAML布局类似,只能返回一个顶级元素。
4.componentDidMount()
在组件第一次绘制之后,会调用 componentDidMount(),通知组件已经加载完成。这个函数调用的时候,其虚拟 DOM 已经构建完成,你可以在这个函数开始获取其中的元素或者子组件了。需要注意的是,RN 框架是先调用子组件的 componentDidMount(),然后调用父组件的函数。从这个函数开始,就可以和 JS 其他框架交互了,例如设置计时 setTimeout 或者 setInterval,或者发起网络请求。这个函数也是只被调用一次。这个函数之后,就进入了稳定运行状态,等待事件触发。
5.componentWillReceiveProps(nextProps)
当组件接收到新的props时,会触发该函数。在该函数中,通常可以调用setState()来完成对stated的修改。
输入参数 nextProps 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 render() 调用。
6.shouldComponentUpdate(nextProps,nextState)
返回布尔值(决定是否需要更新组件)
输入参数 nextProps 和上面的 componentWillReceiveProps 函数一样,nextState 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 true 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。
默认情况下,这个函数永远返回 true 用来保证数据变化的时候 UI 能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定 UI 是否需要更新,能有效提高应用性能。
7.componentWillUpdate(nextProps,nextState)
shouldComponentUpdate返回true或者调用forceUpdate之后,就会开始准更新组件,并调用 componentWillUpdate()。
输入参数与 shouldComponentUpdate 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 this.setState 来修改状态。这个函数调用之后,就会把 nextProps 和 nextState 分别设置到 this.props 和 this.state 中。紧接着这个函数,就会调用 render() 来更新界面了。
8.componentDidUpdate( )
虚拟DOM同步到DOM中后,执行该方法,可以在这个方法中做DOM操作。
除了首次render之后调用componentDidMount,其它render结束之后都是调用componentDidUpdate。
componentWillMount、componentDidMount和componentWillUpdate、componentDidUpdate可以对应起来。区别在于,前者只有在挂载的时候会被调用;而后者在以后的每次更新渲染之后都会被调用。
9.componentWillReceiveProps(nextProps)
当组件接收到新的props时,会触发该函数。在该函数中,通常可以调用setState()来完成对state的修改。
输入参数 nextProps 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 render() 调用。
- React-Native学习总结
- react-native学习(一)
- react-native学习(二)
- React-native学习(一):构建第一个Android项目
- React-Native学习(1)-开发环境的配置
- React Native学习
- React-Native学习
- react-native学习(RN)--之Window环境下搭建环境配置,以及初始化建立react-native项目,(真机和模拟器运行的相关错误解决办法,android打包报错)
- react-native学习(2)
- React-Native中遇到的一些坑(未完待续)
- [React]1:基本语法练习
- mac上配置react-native环境run-ios/run-android命令遇到的问题
- node/electron/react
- [React]react-router跳转传值
- react-native TransformError 错误处理
- 总结真机上运行React Native踩到的那些坑~
- React Native布局篇
- Weex & ReactNative & JSPatch