ReactNative 仿美团项目

2017年11月30日 317点热度 0人点赞 0条评论

图片


今天公司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上面开源项目,接下来也会深入学习,写更多的开源项目来提升自己的能力,也会不断更新笔记。

如有更好的建议请联系:[email protected]

源码请点击:ReactNative 仿美团项目,您喜欢,请读者给star,您的点击会更加增加我的激情,增加更多的开源项目分享给大家,后面我会把ReactNative每一步学习到的东西记录下来,,谢谢。

图片

36800ReactNative 仿美团项目

这个人很懒,什么都没留下

文章评论