(一)前言
我们会遇到一种需求,在用户点击tabbar的时候,需要去判断当前用户是否有权限进入页面,那么我们需要在点击时候处理权限,然后跳转。基于这种需求,我们需要提供一个全局的navigationService.js方案提供全局跳转方案
(二) 版本环境
node 8.0+(v8.12.0)
npm 5.0+(v6.4.1)
java (v1.8.0_172)
"react-native": "0.57.1",
"react": "16.5.0",
"react-navigation": "^2.18.0",
(三) 具体实现
- 我们来实现全局工具库
在utils下新建navigationService.js 文件
import { NavigationActions, StackActions } from 'react-navigation';
let topNavigator;
// 递归查询当前routers
function getCurrRoute(object = {}) {
const { index = 0, routes = [] } = object;
const currRouteMap = routes[index];
if (typeof currRouteMap.index !== 'undefined' && Array.isArray(currRouteMap.routes)) return getCurrRoute(currRouteMap);
return {
currRouteList: routes,
index,
currRouteMap,
};
}
// 获取当前路由
export const getCurrRoutes = () => {
if (!topNavigator) return {};
const {
state: {
nav,
} = {},
} = topNavigator || {};
if (!Object.keys(nav).length) return {};
return getCurrRoute(nav);
};
export const registerTopNavigator = (navigatorRef) => {
topNavigator = navigatorRef;
};
export const reset = (routeName, params) => {
topNavigator.dispatch(StackActions.reset({
index: 0,
actions: [
NavigationActions.navigate({
routeName,
params,
}),
],
}));
};
export const replace = ({
key,
newKey = null,
routeName,
params = null,
action = null,
immediate = null,
}) => {
topNavigator.dispatch(StackActions.replace({
key,
newKey,
routeName,
params,
action,
immediate,
}));
};
export const push = (routeName, params) => {
topNavigator.dispatch(StackActions.push({
routeName,
params,
}));
};
export const pop = (n) => {
topNavigator.dispatch(StackActions.pop({
n,
}));
};
export const navigate = (routeName, params) => {
topNavigator.dispatch(NavigationActions.navigate({
routeName,
params,
}));
};
/**
* Notice! behavior is not always same with props.navigation.goBack in View component
* in the case of nested navigators, use props.navigation.goBack instead!
*/
export const goBack = (key = null) => {
topNavigator.dispatch(NavigationActions.back({ key }));
};
这里我们单例对象设计,将topNavigator变量不做暴露,通过registerTopNavigator方法实现初始化。然后提供react-navigation常用的reset,replace,push,pop,navigate,goBack方法,然后通过递归提供getCurrRoutes方法,让外部能得到当前的路由。
- 我们现在常量文件定义顶层路由和使用createSwitchNavigator创建权限的路由配置
// constants/routers.js 代码如下
export default {
// initial loading Stack
authLoading: 'app.authLoading',
// ...
}
// constants/index.js 代码如下
import routers from './routers';
// tabBar顶层路由
const tabBarTopRouterList = [
routers.xx1, // 这里自己乱写的
routers.xx2,
routers.xx3,
routers.xx4,
];
// 权限顶层路由
const authTopRouterList = [
routers.signIn,
];
// 返回默认路由
const tabViewTopRouterName = routers.xx1;
export {
routers,
tabBarTopRouterList,
authTopRouterList,
tabViewTopRouterName,
};
- 然后我们在全局index.js 入口绑定ref和覆盖安卓默认返回事件
import Navigator from './pages';
import { Provider } from 'mobx-react';
import { BackHandler } from 'react-native';
// constants
import { theme, tabBarTopRouterList, authTopRouterList, tabViewTopRouterName } from './constants';
// models
import RootStore from './models';
// utils
import { goBack, registerTopNavigator, getCurrRoutes, navigate } from './utils/navigationService';
class App extends React.Component {
componentDidMount() {
BackHandler.addEventListener('hardwareBackPress', this.onPressAndroidBack);
}
componentWillUnmount() {
BackHandler.removeEventListener('hardwareBackPress', this.onPressAndroidBack);
}
onPressAndroidBack = () => {
const {
currRouteMap: {
routeName,
params = {},
} = {},
} = getCurrRoutes();
if (!routeName) return true;
// handle root stack
if (tabBarTopRouterList.includes(routeName)) {
BackHandler.exitApp();
return false;
}
// handle auth stack
if (authTopRouterList.includes(routeName)) {
navigate(params.fromRouteId || tabViewTopRouterName);
return true;
}
// back to the previous page
goBack();
return true;
};
// ....
render() {
return (
<Provider rootStore={RootStore}> // 这里你可以将mobx换为redux
<Navigator
ref={registerTopNavigator}
/>
</Provider>
)
}
}
这里我通过onPressAndroidBack实现覆盖安卓默认返回事件。
- 找到你的TabStack的根路由,通过createBottomTabNavigator创建,代码如下
import { AsyncStorage } from 'react-native';
import { createBottomTabNavigator } from 'react-navigation';
import { routers } from '../../../constants';
import { getCurrRoutes } from '../../../utils/navigationService';
// pages 路由变量乱写的,请自行修改
import XX1Screen from './XX1';
import XX2Screen from './XX2';
import XX3Screen from './XX3';
import XX4Screen from './XX4';
const RouteConfig = {
[routers.xx1]: XX1Screen,
[routers.xx2]: XX2Screen,
[routers.xx3]: XX3Screen,
[routers.xx4]: XX4Screen,
};
const NavigatorConfig = {
initialRouteName: routers.xx1,
tabBarOptions: {
activeTintColor: '#fff',
activeBackgroundColor: '#e4393c',
inactiveTintColor: '#e4393c',
inactiveBackgroundColor: '#fff',
labelStyle: {
fontSize: 13,
height: 18,
},
style: {
height: 61,
backgroundColor: '#fff',
shadowOpacity: 0.05,
shadowRadius: 2,
shadowColor: '#000',
shadowOffset: { width: 0, height: -2 },
elevation: 2,
},
tabStyle: {
flexDirection: 'column',
flexWrap: 'nowrap',
alignItems: 'center',
},
},
navigationOptions: () => ({
tabBarOnPress: async ({ defaultHandler, navigation }) => {
const {
state: {
routeName = '',
} = {} } = navigation;
// 拦截路由
if (routeName === routers.xx1 || routeName === routers.xx2) {
const token = await AsyncStorage.getItem('token');
const {
currRouteMap: formRouteMap,
} = getCurrRoutes();
if (!token) {
navigation.navigate(routers.auth, { fromRouteId: formRouteMap.routeName });
return;
}
}
// 默认事件
defaultHandler && defaultHandler();
},
}),
};
const TabStack = createBottomTabNavigator(RouteConfig, NavigatorConfig);
TabStack.navigationOptions = {
header: null,
};
export default TabStack;
这里通过tabBarOnPress事件,在全局的方法下拿到当前的路由,然后通过本地存储的token判断权限,就可以实现拦截权限。当然因为顶层用的createSwitchNavigator方法,在权限(AuthStack)中,你还需要应该使用以下方案navigate push压入栈中,跳转路由,而不是goBack
this.props.navigation.navigate(fromRouteId);
(四) 总结
在web中 react-router-dom提供 history方案,而react-native只能自己定义全局的路由方案,而且全局路由可以提供在状态管理中提供路由跳转方案。
因为不通过redux或者mobx依赖,那么兼容方案,就不需要考虑状态管理移植问题,况且,就单纯封装程度的解藕来看,建议能单纯用react实现的功能,比如纯组件,基本插件封装,尽量不藕合状态管理,因为我也遇到一次用别人插件,在1.3版本不集成redux,但是到1.4却全部在redux中处理,导致我使用mobx根本无法集成。

本文介绍了一种在React Native应用中实现全局路由管理的方法,通过创建navigationService.js工具库,封装了react-navigation常用方法,实现了权限校验和路由跳转功能。
&spm=1001.2101.3001.5002&articleId=85225353&d=1&t=3&u=e8c581a52bc5401cba270916d0a0e406)
568

被折叠的 条评论
为什么被折叠?



