###0.前言
本系列文章主要是对react-native学习知识的实践,并记录下实操过程中遇到的问题和解决方案。
开发环境:windows10 + vscode + react-native 0.57 + Android模拟器(暂时没测试iOS效果)
本文主要是采用react-native编写BOSS直聘的app
的相关UI,以此实践和校验之前学习的react-native知识点。
本文主要讲解内容点:
- 项目文件夹功能划分和思考
- 首页框架搭建(react-navigation的使用)
- 编写过程中遇到的问题和注意点
###1.效果图
通过效果图对本文所讲述的内容有个大概的认知。
###2.项目创建与文件夹划分
####2.1目录说明
- app:存放整个react-native项目的根目录
- assets:存放一些资源文件,例如:json文件、HTML文件等
- images:存放静态的图片资源文件
- src:源码目录,主要存放项目组件源码
- styles:存放组件使用的style
文件夹划分的思考:
- 以App作为根目录是为了方便整个项目的管理,减少react-native的创建目录下的文件数
- assets和images主要为了存放资源以便快速查找。
- src源码目录,底下进行模块划分(迅速查找和多人协作)
- style主要分离src目录中组件的style样式,即样式和组件的业务分离,使组件的代码数减少。
- src下的通用组件components的样式不作分离,以便移植复用。
- 文件夹的划分不是必须按照这种方法,以个人习惯或者团队约定划分为主。
###3.首页框架的搭建
如预览图所示,首页主要为一个底部导航+4个页面组成,采用react-navigation
库实现。
####3.1 createStackNavigator与createBottomTabNavigator的使用
- createStackNavigator:组件,用于创建一个存放页面的堆栈。类似Android的activity栈。即后进先出的一个容器。
- createBottomTabNavigator:组件,创建底部选项卡的导航。
具体实现可直接查看源代码,叙述过多反而没看代码直接。页尾附项目git链接。
####3.2 主要注意点
createStackNavigator与createBottomTabNavigator配合使用可以实现底部导航切换和开启新页面,但需要注意组件是存放在StackNavigator中还是BottomTabNavigator,它们的效果不相同:
- 存放在BottomTabNavigator中的组件打开后,底部导航栏依然存在
- 存放在StackNavigator中的组件根据调用函数可以直接打开新页面或者从栈中弹出指定界面
本项目是通过底部菜单切换4个页面,详情页不需要显示底部菜单。所以采用顶级导航StackNavigator+子级TabNavigator
核心代码:
const MainStackNavigator = createStackNavigator ( //顶级导航StackNavigator
{
Main: {
screen:MainTabNavigator //子级TabNavigator
},
JobDetail:{
screen:JobDetail
}
},
{
initialRouteName:'Main',
headerMode:'none'
}
);
###4.开发中遇到的问题和注意点
学习过程可能很顺利,但在实际开发中可能会遇到各式各样的问题。
####4.1 实现消息页面的(聊天<=>互动)切换。
使用createMaterialTopTabNavigator实现选项卡切换功能。
存在问题:
MaterialTopTabNavigator提供的样式不太符合UI需求。tab的样式需要自定义。
自定义的方式,根据官网介绍是自定义tabBarComponent
,不过官网和网络上的资料特别少,对源码的掌握不足。
所以我选择了折中的方法:
聊天
和互动
作为两个按钮,在外部控制MaterialTopTabNavigator的切换
实现的思路:
- MaterialTopTabNavigator设置tabBar隐藏,即高度为0.
- 设置全局的切换状态state
- 监听MaterialTopTabNavigator的滑动修改切换状态state
核心实现代码:
1.监听滑动事件(onNavigationStateChange)
核心代码:
<MaterialTopTabNavigator
ref={tabNavRef => { //先忽略此句代码,后面讲解
NavigationService.setTopLevelNavigator(tabNavRef);
}}
onNavigationStateChange={(prevNav, nav, action) => {
if(nav.routes[nav.index].routeName === 'Message'){
this.setState({routeIndex:0});
}else{
this.setState({routeIndex:1});
}
routes = nav.routes;
}}
/>
通过onNavigationStateChange可以监听到页面的滑动显示。通过nav.routes[nav.index].routeName知道当前显示的选项卡,并修改全局切换状态routeIndex
的值
2.外部控制导航的切换
在导航内的界面如果需要切换到同一个路由的其他界面,通常可以采用this.props.navigation.navigate('key')
或者this.props.navigation.push('key')
进行跳转。
可是外部组件无法直接获取导航的navigate('key')
和push('key')
方法。
所以官方提供了一种扩展方法让使用者在外部调用路由的跳转方法.使用说明文章地址:点击此处
核心实现:组件的dispatch方法+NavigationActions的navigate.
核心代码:
// NavigationService.js,这个算是一个工具类
import { NavigationActions } from 'react-navigation';
let _navigator;
function setTopLevelNavigator(navigatorRef) {
_navigator = navigatorRef;
}
function navigate(routeName, params) {
_navigator.dispatch(
NavigationActions.navigate({
routeName,
params,
})
);
}
// add other navigation functions that you need and export them
export default {
navigate,
setTopLevelNavigator,
};
使用方式:
1. 组件中设置ref到NavigationService中
2. 在需要处使用NavigationService.navigate('ChatScreen', { userName: 'Lucy' });
核心代码:
1.初始化NavigationService
<MaterialTopTabNavigator
ref={tabNavRef => { //设置NavigationService中的_navigator
NavigationService.setTopLevelNavigator(tabNavRef);
}}
...省略
}}
/>
2.使用方式,在外部点击事件中使用
<TouchableWithoutFeedback
onPress={()=>{
if(this.state.routeIndex != 0){
this.setState({routeIndex:0});
NavigationService.navigate('Message',null); //调用切换页面
}
}}
>
...
</TouchableWithoutFeedback>
####4.2 存在的不足点
onNavigationStateChange监听的是页面的显示和隐藏状态,通过此监听修改外部按钮状态可能出现延迟(state刷新页面延迟)。
此处标记此问题,后期加深了解后寻求解决方案。
###总结
实践所遇到的问题比学习需要思考的多很多,实践可以更快的掌握知识点和扩展知识的使用。
###附
项目地址:点击这里
END
– Nowy
– 2018.11.07