您的位置:首页 > Web前端 > React

react-native学习

2019-08-12 22:11 981 查看
版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/weixin_41767962/article/details/87118688

第一章

  1. 启动页
    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}
/>
);
}
}
  1. 自己构建组件后,要传相应的属性值

组件构成如下:

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() 调用。

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: