React-Native 之 项目实战(一)

前言


  • 本文有配套视频,能够酌情观看。
  • 文中内容因各人理解不一样,可能会有所误差,欢迎朋友们联系我。
  • 文中全部内容仅供学习交流之用,不可用于商业用途,如所以引发的相关法律法规责任,与我无关。
  • 如文中内容对您形成不便,烦请联系 277511806@qq.com 处理,谢谢。
  • 转载麻烦注明出处,谢谢。
  • 资料:连接: https://pan.baidu.com/s/1b3abwy 密码: k8p5php

  • 源码托管到 github 上,须要源码的 点我下载,喜欢的话记得 Star,谢谢!react

ES5转ES6


项目简介


  • 先来看下咱们仿照的这款APP的效果:

最终效果图.gif

  • 从上图中,咱们能够看出复杂度并不大,可是时间关系咱们尽可能将全部的模块都作完,并完善细节。

译注:android

  • 建议打开 视频 配合 文字 学习,以避免有某些细节文中没有提到,但以文中内容为准(根据反馈进行相应更新)ios

  • 之因此选择这款APP,和我我的的爱好有关,固然关键仍是由于这个APP总体并不复杂,包含了市面上常见APP的样式,而且很顺利地就获取到全部请求参数和图片资源,很适合咱们体验 React-native 大体的开发流程。git

项目分析


  • 在开发APP前,产品经理大体会进行需求的分析,而后开会讨论开发过程当中须要使用到的技术、会遇到的难点、分配相应任务、倾听开发人员意见并进行相应的修改,最终肯定总体原型图、开发流程、技术、周期等等,固然其中还有UI的介入,咱们没有产品经理,UI也有现成的,因此大体给你们划分如下几块:es6

    • 需求分析:这款APP主要是经过抓取各大电商平台的 商品优惠信息 进行筛选、分类并最终展示给用户,使用户能够方便、快捷、实时的获取高质量的优惠信息。github

    • 开发模型:咱们这边相似基于 原型模型 开发。json

    • 使用的技术:React-Nativereact-native

    • 功能模块:主要分为 首页、海淘模块、小时风云榜 三大模块等其它附属模块(酌情增长)。api

    • 总体架构:
      • 主体:由 TabBar 做为主体框架,以 首页、海淘模块、小时风云榜 为总体模块,根据 原型图 的效果选择相应的跳转方式
      • 数据展现:根据 原型图 选择相应的数据展现方式
    • 命名规则:参考 编码规范文档(不一样公司之间都有差别,具体看公司提供的文档,这边先遵照下面提到的规则便可)

  • 测试:MDZZ,谁测试→→!

工程环境配置


  • 全部须要用到的资源点击下载

  • 首先,来配置 iOS 端。
  • 将压缩包内的 Images.xcassets 文件夹直接替换掉咱们iOS工程中的 Images.xcassets 文件夹。
  • 这时候咱们能够看到全部图片资源已经成功导入到iOS工程中,接着咱们点击工程文件进行一些必要的配置。
  • General —— App Icons and Launch Images —— 修改 Launch Images SourceImages.xcassets 文件夹内的 LaunchImage ,清除 Launch Screen File 内容。
  • General —— Deployment Info —— Device Orientation —— 只保留 Portrait 选项。
  • 打开 info.plist 文件,找到 Bundle name 选项,将其内容修改成 逛丢学习
  • 打开 info.plist 文件,找到 App Transport Security Settings 选项,给其添加 Allow Arbitrary Loads 选项并设置内容为 YES (若是使用 IPV6标准 能够忽略这一步)
  • OK,至此 iOS 端配置完毕。

iOS配置后效果.gif

  • 接着,来配置 Android 端。
  • 将压缩包内的 drawable-xxhdpi 文件夹复制粘贴到 GD/android/app/src/main/res/ 中。
  • 设置 APP图标 进入 GD/android/app/sec/ 打开 AndroidManifest 文件,修改 android:icon 项,以下:

    <applicatio>
            android:icon="@drawable/icon"
        </application>
  • 设置 APP名称 进入 GD/android/app/src/main/res/values/ 中,打开 strings.xml 文件,作以下修改:

    <resources>
            <string name="app_name">逛丢学习</string>
        </resources>
  • OK,至此 Android 配置完毕。

Android配置后效果.gif

目录结构与命名规则


  • 为了方便理解,咱们这边先不按照常规的React-native开发结构进行开发,后续章节再慢慢转变
  • 这边咱们将文件分为 main(入口)、home(首页)、ht(海淘)、hourList(小时风云榜) 4大部分,将相关的文件放入对应的文件夹,避免开发中频繁切换文档给新手带来烦躁感
  • 命名规则:
    • 文件夹命名方式咱们就跟着 React-Native 默认的方式,采用 小写 + 下划线 进行命名
    • 文件命名方式咱们采用 前缀(大写) + 模块名称(帕斯卡) 的方式进行命名
    • 函数、常量、变量等使用 驼峰命名规则

目录结构:

译注:

  • 驼峰命名规则:首字母小写,后续单词以大写开头,详情点击 驼峰命名 查看阅读。
  • 帕斯卡命名规则:和驼峰相似,只不过将首字母改成大写,详情点击 帕斯卡命名 查看阅读。
  • 下划线命名规则:就是使用下划线分割单词。

第三方框架


  • 这边来说下在 React-Native 中怎么导入第三方框架

  • 首先,第三方框架确定是要到 GitHub 找喽。
  • 在搜索框内搜索 react-native-tab-navigator
  • 在下面的 说明 中告诉咱们了,使用终端 —— 进到工程的主目录下 —— 复制命令行()—— 回车 —— 等待下载完成就导入到工程中了。
  • 到此,第三方框架导入完成,使用在下面会提到。

主体框架搭建


  • 上面提到使用 TabBar 做为主体框架,可是官方只提供了iOS端的 TabBarIOS ,时间缘由为了加快开发进度,而且顺带讲解 第三方框架使用 因此咱们使用 <react-native-tab-navigator>进行开发

  • 既然要使用框架,确定要先引入框架文件。

// 引用第三方框架
   import TabNavigator from 'react-native-tab-navigator';
  • 根据 使用说明 文档能够看出,使用方法和官方的 TabBarIOS 相似(不清楚的麻烦参考React Native 之 TabBarIOS和TabBarIOS.Item使用),因此咱们把 三大模块 添加进TabBar,而且各个模块都是以 Navigator 的形式存在。
export default class GD extends Component {

    // ES6
    // 构造
      constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            selectedTab:'home',
        };
      }

    // 返回TabBar的Item
    renderTabBarItem(title, selectedTab, image, selectedImage, component) {
        return(
            <TabNavigator.Item
                selected={this.state.selectedTab === selectedTab}
                title={title}
                selectedTitleStyle={{color:'black'}}
                renderIcon={() => <Image source={{uri:image}} style={styles.tabbarIconStyle} />}
                renderSelectedIcon={() => <Image source={{uri:selectedImage}} style={styles.tabbarIconStyle} />}
                onPress={() => this.setState({ selectedTab: selectedTab })}>
                    // 添加导航功能
                <Navigator
                        // 设置路由
                    initialRoute={{
                        name:selectedTab,
                        component:component
                    }}
                        
                    renderScene={(route, navigator) => {
                        let Component = route.component;
                        return <Component {...route.params} navigator={navigator} />
                    }}
                />
            </TabNavigator.Item>
        );
    }

    render() {
        return (
            <TabNavigator>
                {/* 首页 */}
                {this.renderTabBarItem("首页", 'home', 'tabbar_home_30x30', 'tabbar_home_selected_30x30', Home)}
                {/* 海淘 */}
                {this.renderTabBarItem("海淘", 'ht', 'tabbar_abroad_30x30', 'tabbar_abroad_selected_30x30', HT)}
                {/* 小时风云榜 */}
                {this.renderTabBarItem("小时风云榜", 'hourlist', 'tabbar_rank_30x30', 'tabbar_rank_selected_30x30', HourList)}
            </TabNavigator>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
    },
    tabbarIconStyle: {
        width:Platform.OS === 'ios' ? 30 : 25,
        height:Platform.OS === 'ios' ? 30 : 25,
    }
});
  • 至此,主体框架搭建完毕。

主体框架效果.gif

自定义导航栏样式


  • 从效果图中能够看出,导航栏的样式都差很少,由于咱们前面已经设置了 Navigator ,这边的话咱们还须要自定义 Navigator 的样式,能够看到全部的 Navigator 样式都是相近的,因此这边咱们就抽出来,让全部的 Navigator 共用一个组件就能够了。

  • 那么首先咱们在 main 文件夹中建立 GDCommunalNavBar 文件并初始化一下里面基本的内容

  • 接着,咱们来看下首页的导航栏,首页导航栏分别有左中右三个按钮,左边为半小时热门,中间为点击下拉显示支持筛选的平台的列表,右边则是商品搜索,一般 Navigator 也只有这3个组件,为了使用者高度地自定义,这边咱们只在 currencyNavBar 中设置3个组件的布局,而后提供接口,获取外部传入的值,并在内部判断是否须要建立相应的组件。

export default class GDCommunalNavBar extends Component {

    static propTypes = {
        leftItem:PropTypes.func,
        titleItem:PropTypes.func,
        rightItem:PropTypes.func,
    };

    // 左边
    renderLeftItem() {
        if (this.props.leftItem === undefined) return;
        return this.props.leftItem();
    }

    // 中间
    renderTitleItem() {
        if (this.props.titleItem === undefined) return;
        return this.props.titleItem();
    }

    // 右边
    renderRightItem() {
        if (this.props.rightItem === undefined) return;
        return this.props.rightItem();
    }

    render() {
        return (
            <View style={styles.container}>
                {/* 左边 */}
                <View>
                    {this.renderLeftItem()}
                </View>
                {/* 中间 */}
                <View>
                    {this.renderTitleItem()}
                </View>
                {/* 右边 */}
                <View>
                    {this.renderRightItem()}
                </View>
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        width:width,
        height:Platform.OS === 'ios' ? 64 : 44,
        backgroundColor:'white',
        flexDirection:'row',
        justifyContent:'space-between',
        alignItems:'center',
        borderBottomWidth:0.5,
        borderBottomColor:'gray',
        paddingTop:Platform.OS === 'ios' ? 15 : 0,
    },
});
  • 这边咱们就已经完成了 Navigator 的样式,咱们到首页来用一下,看好很差用,使用这边就不说了(1.引用外部文件;2.<CommunalNavBar ...参数/>)

[Upload 自定义Navigator样式.gif failed. Please try again.]

首页半小时热门


  • 这边咱们就先从 半小时热门 开始,像这样的数据展现,咱们确定是优先选择 ListView ,其中,cell 的样式分解以下:

cell样式.png

  • 咱们先将数据请求下来,肯定正确获取到数据后,再来定义 cell 的样式。

  • 接下来咱们来自定义一下 cell 样式

export default class GDCommunalNavBar extends Component {

    static propTypes = {
        image:PropTypes.string,
        title:PropTypes.string,
    };

    render() {
        return (
            <View style={styles.container}>
                {/* 左边图片 */}
                <Image source={{uri:this.props.image}} style={styles.imageStyle} />
                {/* 中间的文中 */}
                <View>
                    <Text numberOfLines={3} style={styles.titleStyle}>{this.props.title}</Text>
                </View>
                {/* 右边的箭头 */}
                <Image source={{uri:'icon_cell_rightArrow'}} style={styles.arrowStyle} />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flexDirection:'row',
        alignItems:'center',
        justifyContent:'space-between',
        backgroundColor:'white',
        height:100,
        width:width,
        borderBottomWidth:0.5,
        borderBottomColor:'gray',
        marginLeft:15

    },

    imageStyle: {
        width:70,
        height:70,
    },
    titleStyle: {
        width:width * 0.65,
    },
    arrowStyle: {
        width:10,
        height:10,
        marginRight:30
    }
});
  • 好了,到这里 cell 样式也定义完成而且效果是同样的。
export default class GDHalfHourHot extends Component {

    // 构造
      constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            dataSource: new ListView.DataSource({rowHasChanged:(r1, r2) => r1 !== r2}),
        };
        // 绑定
        this.fetchData = this.fetchData.bind(this);
      }

    // 网络请求
    fetchData() {
        fetch('http://guangdiu.com/api/gethots.php')
            .then((response) => response.json())
            .then((responseData) => {
                this.setState({
                    dataSource: this.state.dataSource.cloneWithRows(responseData.data)
                });
            })
            .done()
    }

    popToHome() {
        this.props.navigator.pop();
    }

    // 返回中间按钮
    renderTitleItem() {
        return(
            <Text style={styles.navbarTitleItemStyle}>近半小时热门</Text>
        );
    }

    // 返回右边按钮
    renderRightItem() {
        return(
            <TouchableOpacity
                onPress={()=>{this.popToHome()}}
            >
                <Text style={styles.navbarRightItemStyle}>关闭</Text>
            </TouchableOpacity>
        );
    }

    // 返回每一行cell的样式
    renderRow(rowData) {
        return(
            <CommunalHotCell
                image={rowData.image}
                title={rowData.title}
            />
        );
    }

    componentDidMount() {
        this.fetchData();
    }

    render() {
        return (
            <View style={styles.container}>
                {/* 导航栏样式 */}
                <CommunalNavBar
                    titleItem = {() => this.renderTitleItem()}
                    rightItem = {() => this.renderRightItem()}
                />

                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow}
                    showsHorizontalScrollIndicator={false}
                    style={styles.listViewStyle}
                />
            </View>
        );
    }
}

const styles = StyleSheet.create({
    container: {
        flex:1,
        alignItems: 'center',
    },

    navbarTitleItemStyle: {
        fontSize:17,
        color:'black',
        marginLeft:50
    },
    navbarRightItemStyle: {
        fontSize:17,
        color:'rgba(123,178,114,1.0)',
        marginRight:15
    },

    listViewStyle: {
        width:width,
    }
});

近半小时热门.gif

  • 从效果图中能够看出,咱们还少了上面的提示标题,这边很简单,咱们也来快速完成一些
{/* 顶部提示 */}
    <View style={styles.headerPromptStyle}>
        <Text>根据每条折扣的点击进行统计,每5分钟更新一次</Text>
    </View>

样式部分:

headerPromptStyle: {
        height:44,
        width:width,
        backgroundColor:'rgba(239,239,239,0.5)',
        justifyContent:'center',
        alignItems:'center'
    }

提示标题补充.png

隐藏于显示TabBar之通知的使用


  • 配置TabBar隐藏与显示条件
// ES6
    // 构造
      constructor(props) {
        super(props);
        // 初始状态
        this.state = {
            selectedTab:'home',
            isHiddenTabBar:false,   // 是否隐藏tabbar
        };
      }
      
   <TabNavigator
                tabBarStyle={this.state.isHiddenTabBar !== true ? {} : {height:0, overflow:'hidden'}}
                sceneStyle={this.state.isHiddenTabBar !== true ? {} : {paddingBottom:0}}
            >
                {/* 首页 */}
                {this.renderTabBarItem("首页", 'home', 'tabbar_home_30x30', 'tabbar_home_selected_30x30', Home)}
                {/* 海淘 */}
                {this.renderTabBarItem("海淘", 'ht', 'tabbar_abroad_30x30', 'tabbar_abroad_selected_30x30', HT)}
                {/* 小时风云榜 */}
                {this.renderTabBarItem("小时风云榜", 'hourlist', 'tabbar_rank_30x30', 'tabbar_rank_selected_30x30', HourList)}
            </TabNavigator>
  • 这边咱们引入新的知识 —— 通知

  • 使用通知很简单,首先须要注册通知并在适当的地方进行销毁

componentDidMount() {
        // 注册通知
        this.subscription = DeviceEventEmitter.addListener('isHiddenTabBar', (data)=>{this.tongZhi(data)});
    }

    componentWillUnmount() {
        // 销毁
        this.subscription.remove();
    }
  • 接着在咱们须要的地方发送通知
componentWillMount() {
        // 发送通知
        DeviceEventEmitter.emit('isHiddenTabBar', true);
    }

    componentWillUnmount() {
        // 发送通知
        DeviceEventEmitter.emit('isHiddenTabBar', false);
    }

隐藏显示TabBar.gif

相关文章
相关标签/搜索