编程iOS开发笔记iOS、Swift、React Native

ReactNative 仿美团项目

2017-11-29  本文已影响5697人  博行天下

今天公司iOS项目完成了,在闲暇时候回顾一下上半年写过的ReactNative 仿美团项目,感觉好久好久没有再动过ReactNative混合模式了,对于ReactNative中ES6很是熟练,在这段时间几乎每天都用Flex ES6语法糖来写手机端页面,对于web前端手机页面也有了一定的了解,为了ReactNative项目能够更加熟练的编写,也积累了很多前端知识,学习永无止境,但是实战项目是使自己增长最快的方法,今天为大家分享ReactNative 仿美团项目,和大家一起学习。

一、第一部分直接上代码,先了解下项目结构

1、仿美团项目:设置标签栏和导航栏

导航栏和标签栏.png

核心代码:

JavaScript

var LBRNMain = React.createClass({

    getInitialState(){
      return {
         selectedTab:'Home'
       }
    },
render() {
      return (
        <TabNavigator>

            {this.childNavigetor('首页','Home','icon_tabbar_homepage','icon_tabbar_homepage_selected','Home',LBRNHome)}
            {this.childNavigetor('商家','EB','icon_tabbar_merchant_normal','icon_tabbar_merchant_selected','EB',LBRNEB)}
            {this.childNavigetor('我的','Mine','icon_tabbar_mine','icon_tabbar_mine_selected','Mine',LBRNMine)}
            {this.childNavigetor('更多','More','icon_tabbar_misc','icon_tabbar_misc_selected','More',LBRNMore)}
       </TabNavigator>
);
},

childNavigetor(title,tabName,normalImage, selectedImage,componentName,component){
     return (
       <TabNavigator.Item
            selectedTitleStyle={styles.selectedTextStyle}
            selected={this.state.selectedTab === tabName}
            title={title}
            renderIcon={() => <Image source={{uri:normalImage}} style={styles.iconStyle} />}
            renderSelectedIcon={() => <Image source={{uri:selectedImage}} style={styles.iconStyle} />}
            onPress={() => this.setState({ selectedTab: componentName })}>
            <Navigator
               initialRoute={{ name: componentName, component: component }}
               configureScene={(route) => {
               return Navigator.SceneConfigs.PushFromRight;
               }}
               renderScene={(route, navigator) => {
               let Component = route.component;
               return <Component {...route.passProps} navigator={navigator} />
               }}
            />

     </TabNavigator.Item>
    )
  }
})

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
      },
    iconStyle:{
        width:28,
        height:28
    },
        selectedTextStyle:{
        color:'#fb6320'
    }
});

module.exports = LBRNMain;

2、 加载启动图片

核心代码:

JavaScript

var LBRNLaunchImage = React.createClass({

    render(){
       return(

         <Image source={{uri:'welcome.png'}} style={styles.container} />
       )
    },
    //增加定时器、请求网络数据
    componentDidMount(){
      setTimeout(()=>{
      this.props.navigator.replace({
      component:LBRNMain
      })
      },1000)
    }
})

const styles=StyleSheet.create({
   container:{
   flex:1
  }
})

module.exports=LBRNLaunchImage;

3、更多模块实现
① 错误解决

错误解决.png

解决办法:cd进入项目根目录执行如下安装命令

react-native bundle --platform android --dev false --entry-file index.android.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res/

② 正确截图

zongduan.png

③ 错误截图

错误截图.png

4、导入文件方式

第一种方式
import SmallMiddleView from './SmallMiddleView.js';
第二种方式
SmallMiddleView = require('SmallMiddleView');

5、我的模块

我的界面.png

核心代码:

JavaScript

var width = require('Dimensions').get('window').width;
var LBRNMineCell = require('./LBRNMineCell');
var LBRNMine = React.createClass({
        render(){
            return (
                <View style={styles.container}>
                    <View style={styles.backgroundStyle}>
                    </View>
                    <View style={{position:'absolute',marginTop:-300}}>
                        <ScrollView>
                            <View style={{flexDirection:'row',justifyContent:'space-between',alignItems:'center',marginTop:30}}>
                                <View style={{flexDirection:'row',alignItems:'center',backgroundColor:'#FB6320'}}>
                                    <Image source={{uri:'wm'}} style={{width: 80,height:80,borderRadius:40}}/>
                                    <Text style={{color:'red',fontSize:18}}>LBRNMeiTuan</Text>
                                    <Image source={{uri:'avatar_vip'}} style={{width: 20,height:20,marginLeft:5}}/>
                                </View>
                                <TouchableOpacity>
                                    <Image source={{uri:'icon_cell_rightarrow'}} style={{width: 20,height:20,marginRight:10}}/>
                                </TouchableOpacity>
                            </View>
                            {/*美团劵、评价、收藏*/}
                            <View style={{height:60,width:width,backgroundColor:'#FC8135',flexDirection:'row',marginTop: 20}}>
                                {this.renderViewMethod('500','美团劵')}
                                <View style={{backgroundColor:'#ddd',height:56,marginTop:2,width:0.5}}></View>
                                {this.renderViewMethod('500','评价')}
                                <View style={{backgroundColor:'#ddd',height:56,marginTop:2,width:0.5}}></View>
                                {this.renderViewMethod('500','收藏')}
                            </View>
                            {/*待付款、待使用、待评价、退货/售后*/}
                            <View style={{height:80,width:width,backgroundColor:'white',flexDirection:'row'}}>
                                {this.renderImageMethod('order1','待付款')}
                                {this.renderImageMethod('order2','待使用')}
                                {this.renderImageMethod('order3','待评价')}
                                {this.renderImageMethod('order4','退货/售后')}
                            </View>
                            <View style={{height:20,width:width,backgroundColor: '#DCDCDB'}}>
                            </View>
                            <View>
                                <LBRNMineCell
                                    title='我的钱包'
                                    iconLeftString='pay'
                                    arrowString='icon_cell_rightarrow'
                                    // rightImageString=''
                                    rightText='帐户余额:&yen;8452'
                                />
                                <LBRNMineCell
                                    title='抵用券'
                                    iconLeftString='card'
                                    arrowString='icon_cell_rightarrow'
                                    rightImageString='icon_hot'
                                    // rightText=''
                                />
                            </View>
                            <View style={{height:20,width:width,backgroundColor: '#DCDCDB'}}>
                            </View>
                            <View >
                                <LBRNMineCell
                                    title='积分商城'
                                    iconLeftString='card'
                                    arrowString='icon_cell_rightarrow'
                                    rightImageString='icon_hot'
                                    // rightText=''
                                />
                            </View>
                            <View style={{height:20,width:width,backgroundColor: '#DCDCDB'}}>
                            </View>
                            <View>
                                <LBRNMineCell
                                    title='今日推荐'
                                    iconLeftString='like'
                                    arrowString='icon_cell_rightarrow'
                                    rightImageString='icon_hot'
                                    // rightText=''
                                />
                            </View>
                            <View style={{height:20,width:width,backgroundColor: '#DCDCDB'}}>
                            </View>
                            <View>
                                <LBRNMineCell
                                    title='我要合作'
                                    iconLeftString='new_friend'
                                    arrowString='icon_cell_rightarrow'
                                    // rightImageString='icon_hot'
                                    rightText='轻松开店,招财进宝'
                                />
                            </View>
                            <View style={{height:100,width:width,backgroundColor: '#DCDCDB'}}>
                            </View>
                        </ScrollView>
                    </View>

                </View>
            );
        },
        renderViewMethod(count,name){
            return(
                <View style={{justifyContent:'center',width:width/3.0,alignItems:'center'}}>
                    <Text style={{color:'white'}}>{count}</Text>
                    <Text style={{color:'white',marginTop:7}}>{name}</Text>
                </View>
                )

        },
        renderImageMethod(imageString,name){
            return(
                <View style={{justifyContent:'center',width:width/4.0,alignItems:'center'}}>
                    <Image source={{uri:imageString}} style={{width:40,height:30}}/>
                    <Text style={{color:'#bbb',marginTop:7}}>{name}</Text>
                </View>
                )

        }
    }
)

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#DCDCDB',
    },
    backgroundStyle:{
        width:width,
        height:300,
        backgroundColor:'#FB6320',
        position:'absolute',
        top:0
    }
});

module.exports = LBRNMine;

6、商家模块

商家.png

核心代码:

JavaScript

var width = require('Dimensions').get('window').width;
var LBRNEB = React.createClass({
    getDefaultProps(){
        return{
          urlString: 'http://i.meituan.com/topic/mingdian?ci=1&f=iphone&msid=48E2B810-805D-4821-9CDD-D5C9E01BC98A2015-07-02-16-25124&token=p19ukJltGhla4y5Jryb1jgCdKjsAAAAAsgAAADHFD3UYGxaY2FlFPQXQj2wCyCrhhn7VVB-KpG_U3-clHlvsLM8JRrnZK35y8UU3DQ&userid=10086&utm_campaign=AgroupBgroupD100Fab_chunceshishuju__a__a___b1junglehomepagecatesort__b__leftflow___ab_gxhceshi__nostrategy__leftflow___ab_gxhceshi0202__b__a___ab_pindaochangsha__a__leftflow___ab_xinkeceshi__b__leftflow___ab_gxtest__gd__leftflow___ab_waimaiwending__a__a___ab_gxh_82__nostrategy__leftflow___i_group_5_2_deallist_poitype__d__d___ab_b_food_57_purepoilist_extinfo__a__a___ab_pindaoshenyang__a__leftflow___ab_pindaoquxincelue0630__b__b1___a20141120nanning__m1__leftflow___ab_i_group_5_3_poidetaildeallist__a__b___ab_waimaizhanshi__b__b1___ab_i_group_5_5_onsite__b__b___ab_i_group_5_6_searchkuang__a__leftflowGhomepage_bargainmiddle_30311731&utm_content=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&utm_medium=iphone&utm_source=AppStore&utm_term=5.7&uuid=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&version_name=5.7&lat=23.12005&lng=113.3076'
        }
    },
    getInitialState(){
        return{
          urlString: 'http://i.meituan.com/topic/mingdian?ci=1&f=iphone&msid=48E2B810-805D-4821-9CDD-D5C9E01BC98A2015-07-02-16-25124&token=p19ukJltGhla4y5Jryb1jgCdKjsAAAAAsgAAADHFD3UYGxaY2FlFPQXQj2wCyCrhhn7VVB-KpG_U3-clHlvsLM8JRrnZK35y8UU3DQ&userid=10086&utm_campaign=AgroupBgroupD100Fab_chunceshishuju__a__a___b1junglehomepagecatesort__b__leftflow___ab_gxhceshi__nostrategy__leftflow___ab_gxhceshi0202__b__a___ab_pindaochangsha__a__leftflow___ab_xinkeceshi__b__leftflow___ab_gxtest__gd__leftflow___ab_waimaiwending__a__a___ab_gxh_82__nostrategy__leftflow___i_group_5_2_deallist_poitype__d__d___ab_b_food_57_purepoilist_extinfo__a__a___ab_pindaoshenyang__a__leftflow___ab_pindaoquxincelue0630__b__b1___a20141120nanning__m1__leftflow___ab_i_group_5_3_poidetaildeallist__a__b___ab_waimaizhanshi__b__b1___ab_i_group_5_5_onsite__b__b___ab_i_group_5_6_searchkuang__a__leftflowGhomepage_bargainmiddle_30311731&utm_content=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&utm_medium=iphone&utm_source=AppStore&utm_term=5.7&uuid=4B8C0B46F5B0527D55EA292904FD7E12E48FB7BEA8DF50BFE7828AF7F20BB08D&version_name=5.7&lat=23.12005&lng=113.3076'
        }
    },
    render(){
        return (
           <View style={styles.container}>
               {this.renderNavbarMethod()}
               {this.webViewMethod()}
            </View>
       );
    },
    renderNavbarMethod(){
        return(
            <View style={styles.ebStyleStyle}>
                <TouchableOpacity style={{marginTop:20,marginLeft:10}}>
                    <Image source={{url:'icon_shop_local'}} style={styles.toolBarIcon}/>
                </TouchableOpacity>
                <View >
                    <Text style={{color: 'white',fontSize:18,marginTop:28,fontWeight:'bold'}}>商家</Text>
                </View>

                <TouchableOpacity style={{marginTop:20,marginRight:10}}>
                    <Image source={{url:'icon_shop_search'}} style={styles.toolBarIcon}/>
                </TouchableOpacity>

            </View>
        )
    },
    webViewMethod(){
        return(
            <WebView
                automaticallyAdjustContentInsets={true}
                source={{uri: this.state.urlString}}
                javaScriptEnabled={true}
                domStorageEnabled={true}
                decelerationRate="normal"
                startInLoadingState={true}
            />
        )
    }
 }
)

const styles = StyleSheet.create({
    container: {
        flex: 1,
        backgroundColor: '#F5FCFF',
    },
    ebStyleStyle:{
        width:width,
        height:Platform.OS === 'ios' ? 64 : 44,
        backgroundColor:'#FB6320',
        flexDirection:'row',
        justifyContent:'space-between',
    },
    toolBarIcon:{
        width:30,
        height:30,
    }
});

module.exports = LBRNEB;

7、首页上部视图

topView.png

核心代码:

JavaScript

// 当滚动动画结束之后调用此回调
onScrollAnimationEnd(event){
     // Math.floor(x)获取不大于x的最大整数
     var page = Math.floor(event.nativeEvent.contentOffset.x/width);
     console.log(page);
     this.setState({
     currentPage:page
  })
},
renderScrollViewMethod(){
     var dataCount = homeTopMenuData;
     var array = [];
     for (var i=0;i<dataCount.length;i++){
        array.push(
           <LBRNHomeTopListView
              dataArray={homeTopMenuData[i]}
              key={i}
           />
         )
      }
      return array;
},
indicatorMethod(){
     var colorsArray = [], bullColor;
     //&bull; 圆点
     for(var i=0;i<2;i++){
           bullColor = i == this.state.currentPage ? 'orange' : '#bbb';
           colorsArray.push(
             <Text style={[{fontSize:22,paddingRight:3}, style={color:bullColor}]} key={i}>&bull;</Text>
           )
     }
     return colorsArray;
 }

var LBRNHomeTopListView = React.createClass({
     getDefaultProps(){
        return{
           dataArray:[]
       }
     },
     getInitialState(){
        let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        return{
           dataSource : ds.cloneWithRows(this.props.dataArray)
         }
      },
    render(){
        return(
           <View>
              <ListView
                  dataSource={this.state.dataSource}
                  renderRow={this.renderRow}
                  contentContainerStyle={styles.contentStyle}
                  scrollEnabled={false}//设置ListView不滑动
               />

          </View>
        )
     },
    //cell
    renderRow(rowData){
        return(
           <View style={{width:imageWH,height:imageWH,justifyContent:'center',alignItems:'center'}}>
              <Image source={{uri:rowData.image}} style={{width:imageWH - 20,height:imageWH - 20}}/>
              <Text>{rowData.title}</Text>
           </View>
        )
       }
 })
注意事项:
JavaScript

// 底部如果是ScrollView,那么根节点就是ScrollView,不要把根节点设置为View
<ScrollView>
   <LBRNHomeTopView />
</ScrollView>
<ListView
    dataSource={this.state.dataSource}
    renderRow={this.renderRow}
    contentContainerStyle={styles.contentStyle}
    scrollEnabled={false}
/>

// 要使ListView换行,要设置ListView宽度
contentStyle:{
    flexDirection:'row',
    flexWrap:'wrap',
    width:width
}

8、首页中间组件以及购物中心组件

购物中心.png

核心代码:

JavaScript

var LBRNHomeShopCenterView = React.createClass({
    getDefaultProps(){
         return{
            dataArray:[]
         }
    },
    getInitialState(){
         let dataSource = new ListView.DataSource({rowHasChanged:(row1,row2) => row1 !== row2});
         return{
           dataSource:dataSource.cloneWithRows(this.props.dataArray)
        }
    },
    render(){
         return(
            <ListView
              dataSource={this.state.dataSource}
              renderRow={this.renderCenterRow}
              contentContainerStyle={styles.contentStyle}
    />

)
},
//cell
renderCenterRow(rowData,sectionID,rowID){
       var imageMarginRight = 0;

      if (this.props.dataArray.length-1 == rowID){
          imageMarginRight = 10;
      }
      return(
     <View >
        <View style={styles.container}>
        <Image source={{uri:rowData.img}} style={{width:130,height:97,borderRadius:10,marginRight:imageMarginRight}}/>
        <Text style={{color:'white',position:'absolute',bottom:20,backgroundColor:'red',fontSize:16}}>{rowData.showtext.text}</Text>

     </View>

     <View >
         <Text style={{fontSize:14,fontWeight:'bold', color:'#bbb',marginTop:5,marginLeft:10,marginBottom:5}}>{rowData.name}</Text>
         </View>
     </View>
  )
 }
})
const styles = StyleSheet.create({
      container:{
          backgroundColor:'white',
          marginLeft:10
      },
      contentStyle:{
          flexDirection:'row',
     }
})
module.exports=LBRNHomeShopCenterView;

9、购物中心详情
购物中心详情页面使用了回调函数、逆向传值和正向传值

购物中心详情.png

核心代码:

JavaScript

getDefaultProps(){
     return{
       dataArray:[],
       popToHome:null
}
},

urlMethod(url){
     ///处理url
    var httpUrl=url.replace('imeituan://www.meituan.com/web/?url=','');

    if (httpUrl == null)return;
    this.props.popToHome(httpUrl);
    //AlertIOS.alert(httpUrl);
}

<LBRNHomeShopCenterView
    dataArray={homeShopCenter.data}
    popToHome={(url)=>this.popToHome(url)}///回调函数
/>

<WebView
    automaticallyAdjustContentInsets={true}
    source={{uri: this.state.detailUrl}}
    javaScriptEnabled={true}
    domStorageEnabled={true}
    decelerationRate="normal"
    startInLoadingState={true}
/>

10、热门中心模块
热门中心模块和购物中心类似
核心代码:

var width = require('Dimensions').get('window').width;
var widthView;
var LBRNHomeHotView = React.createClass({

        getDefaultProps(){
            return{
                data:[],
                popToHot:null
            }
        },
        getInitialState(){
            let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
            if(this.props.data.length == 2){
                widthView = width/2.0;
            }else {
                widthView = width/4;
            }
            return{
                dataSource : ds.cloneWithRows(this.props.data)
            }
        },
        render(){
            return (
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow}
                    contentContainerStyle={styles.contentStyle}
                />
            );
        },
        renderRow(rowData){
            return(
                <View>
                    <TouchableOpacity activeOpacity={0.5} onPress={()=>this.pressMethod(rowData.target)} style={[styles.touchableStyle,{borderRightWidth: 0.5,borderTopWidth: 0.5,borderRightColor:'#bbb',borderTopColor:'#bbb',width:widthView}]}>
                      <Text style={{fontSize:14,color:'black',marginBottom:5}}>{rowData.title}</Text>
                      <Text style={{fontSize:10,color:'orange',marginBottom:5}}>{rowData.subTitle}</Text>
                      <Image source={{uri:rowData.hotImage}} style={{width:50,height:50,borderRadius:25}}/>
                    </TouchableOpacity>
                </View>
            )
        },
        pressMethod(target){

            if (target.length == 0)return;
            this.props.popToHot(target.replace('imeituan://www.meituan.com/web?url=',''));
        }
    }
)


const styles = StyleSheet.create({
    contentStyle:{
        flexDirection:'row'
    },
    touchableStyle:{
        justifyContent:'center',
        alignItems:'center',
        paddingTop:10,
        paddingBottom:10
    }
});

module.exports = LBRNHomeHotView;

11、猜你喜欢
猜你喜欢使用了回调函数、逆向传值和正向传值

猜你喜欢.png

核心代码:


dataMethod(){
      fetch(this.props.api_url)
       .then((responder)=>responder.json())
       .then(responderData=>{
          this.setState({dataSource:this.state.dataSource.cloneWithRows(responderData.data)})
       })
      .catch((error) => {
         this.setState({dataSource:this.state.dataSource.cloneWithRows(homeBottomData.data)})
     });
}

dealWithUrl(url){

    if (url.search('w.h') == -1){
       return url.replace('.webp','');
    }else {
      return url.replace('w.h','120.90')
    }
}

二、第二部分项目运行

在github上面下载代码直接使用命令行git clone https://github.com/lb2281075105/LBRNMeiTuan.git,直接运行可能显示错误,需要执行下面的命令才能运行:
1、首先:【npm install】
2、其次:【react-native-link】
3、最后:【react-native run-ios】
4、如果有什么问题可以github直接issue给我,或者留言给我,一起学习,一起讨论

三、第三部分学习心得

学习ReactNative开发,感觉编写代码心里很舒畅,用JSX语句开发App,很爽快,自学ReactNative,有时间看看ReactNative中文网站资源,就拿美团作为练手项目,也是第一个在github上面开源项目,接下来也会深入学习,写更多的开源项目来提升自己的能力,也会不断更新笔记。

如有更好的建议请联系:2281075105@qq.com
源码请点击:ReactNative 仿美团项目,您喜欢,请读者给star,您的点击会更加增加我的激情,增加更多的开源项目分享给大家,后面我会把ReactNative每一步学习到的东西记录下来,,谢谢。
上一篇下一篇

猜你喜欢

热点阅读