xgrn-navigation
v0.7.0
Published
rn容器-路由模块
Downloads
3
Readme
XGNavigation
RN导航框架
功能
原生页面与js页面导航模块
安装
私有库操作
nrm ls
如果提示nrm命令不存在,如下操作
npm install -g nrm
然后增加私有库地址并使用:
nrm add xgnpm http://172.16.2.71:4873/
nrm use xgnpm
npm install
安装依赖
$ yarn add xgrn-navigation
$ react-native link xgrn-navigation
库升级
$ npm update xgrn-navigation
项目配置
Android
- 修改你的MainApplication改为继承自NavigationApplication:
public class MainApplication extends NavigationApplication implements ReactApplication {
...
}
并实现NavigationApplication的抽象方法:
@Override
public boolean isDebug() {
return BuildConfig.DEBUG;
}
- 修改你的MainActivity改为继承自SplashActivity:
public class MainActivity extends SplashActivity {
/**
* Returns the name of the main component registered from JavaScript.
* This is used to schedule rendering of the component.
*/
@Override
protected String getMainComponentName() {
return "";
}
}
iOS
AppDelegate.m中
#import <XGNavigationController.h>
#import <XGRNBridgeManager.h>
/*------------------------------分割线--------------------------------*/
#pragma mark - 创建应用窗口
- (void)createWindowWithOptions:(NSDictionary *)launchOptions{
// 获取js包的路径
NSURL *jsCodeLocation;
#ifdef DEBUG
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index" fallbackResource:nil];
#else
jsCodeLocation = [[TbbUpdateSDK standardSDK] getLocalBundleUrlAtReleasePackage];
#endif
// 配置通用Bridge
[[XGRNBridgeManager standardManager] loadBridgeWithBundleURL:jsCodeLocation andModuleName:@"jutong" launchOptions:launchOptions];
// 初始化rootViewController
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = [UIColor whiteColor];
self.window.rootViewController = [XGNavigationController createWithLaunchOptions:launchOptions];
}
ios原生页面跳转js页面
#import <XGNavigation/XGNavigation.h>
/*------------------------------分割线--------------------------------*/
// 弱引用VC
__weak typeof(self) weakSelf = self;
JSCallBackBlock callBack = ^(NSDictionary * params){
NSLog(@"%@---%@",params,weakSelf);
};
[XGNavigation push:@{
@"pageType": @"JSPage",
@"pagePath": @"classify/GoodsSearchPage",
@"params": @{
@"onSubmitCallBack": callBack,
}
}
andAnimated:YES];
JS页面代码规范示例
为了自动将应用路由信息标准格式化传递给电商配置中台。 项目中JS页面编写时应当遵循并定义如下参数规范:
页面props参数规范
static propTypes = {
id: PropTypes.string.isRequired,
name: PropTypes.string,
};
页面props参数描述
static propTypesDesc = {
id: '商品id',
name: '商品名称',
};
电商配置中台 和 是否需要登录 配置参数
static xgNavigationBarOptions = {
needLogin: true, //进入该页面是否需要登录
showOnCMS: true, //是否允许CMS配置中台配置跳转
cmsPageTitle: '商品搜索页面', //CMS展示的页面名称
pageName: 'GoodsSearchPage', //路由子path
};
当且仅当showOnCMS为true时,该页面才会加入路由上传表中,方可同步到CMS上。
用法
按要求写好文件层级,便于navigation识别你的js文件路径
修改你的入口App.js文件.仅用于根据配置生成一些的JSView,页面是大家在js中写的page。
//导入XGNavigation
import XGNavigation from 'xgrn-navigation';
export default class App extends Component<{}> {
render() {
//查询是否匹配路由
const page = XGNavigation.renderPageByConfig(this.props);
if (page && page !== 404) {
return page;
} else if (page == 404) {
return (
<View style={styles.container}>
<Text style={styles.welcome} onPress={this._onPress}>
{`App not found 404`}
</Text>
</View>
);
}
return (<LoadingView/>);
}
}
3.路由跳转
XGNavigation会自动为你的每个子页面添加key为navigation的props属性,因此在你的页面中这样使用:
const {navigation} = this.props;
navigation.push({
pagePath: home/HomePage
})
###API介绍
1.pageType
作用:获取支持的页面类型
返回值:
return {
JSPage: 'JSPage', // JS页面
NativePage: 'NativePage', // 原声页面
NativeTabPage: 'NativeTabPage', // 原声tab页面
};
2.transitionsConfig
作用:获取支持的转场动画类型
返回值:
return {
FromRight: 'FromRight', // 从右到左
FromBottom: 'FromBottom',// 从下到上
};
3.appRoutes
作用:app注册的所有JS路由栈
返回值:
{}
5.initializeRoutes(routeConfig)
作用:初始化项目js页面路由信息
使用示例:@param routeConfig
XGNavigation.initializeRoutes([
home, //首页
classify, //分类
shopping, //购物车
mine, //我的
debug, //调试工具
XGAuth //登录、注册
]);
6.match(pathPath)
作用:根据pathPath匹配到页面组件
参数
@param pathPath 页面路由
返回值
组件Component或null
7.renderPageByConfig(initParams)
作用:根据初始化参数返回页面
参数
@param initParams
返回值
@return {*} 返回值可能为一个组件,也可能为404,如果initParams不存在pagePath返回null
8.resetRoot(pageConfig, animated)
作用:重置整个路由栈
@param pageConfig
.pageType String.页面类型:默认是JSPage,目前仅支持(JSPage,NativePage,NativeTabPage)
.transitionsConfig String.转场动画配置:默认是FromBottom,目前仅支持(FromRight,FromBottom,FromTop)
.pagePath String.页面路径(当pageType为JSPage,NativePage时需要需要指定页面初始化参数,代表js中页面的文件路径、或ios中viewcontroller的class名称、或android中active的class名称)
pagePath支持Object{ios: 'DemoViewController',android:'DemoActivety'}
.params Object.页面初始化参数,可为空(当pageType为JSPage,NativePage时需要需要指定页面初始化参数)
.tabConfigs Tab配置(当且仅当pageType===NativeTabPage)
.selectedIndex 默认选中的tab栏(可选)
.tabCount 多少个tab(__ANDROID__)
.tintColor 选中的Icon和title的颜色,可选项
.unselectedItemTintColor 未选中Icon和title的颜色,可选项
.barTintColor tabbar的颜色,可选项
.barTranslucent: false, tabbar半透明选项,barTintColor有值则该选项无效,效果不透明 (__IOS__)
.pages Array<itemParams>.tab每一个item的配置
.pageType 数据类型同上(此时不在支持NativeTabPage)
.pagePath 数据类型同上
.params 数据类型同上
.selectTabBarIcon tab选中icon
.unSelectTabBarIcon tab非选中的icon
.tabBarTitle tab对应的title
@param animated 是否带动画
9.addPushPageInterceptor(pushInterceptor)
作用:添加页面push跳转拦截器函数(目前仅支持js调用时,能进行拦截)
使用示例:
@param targetPageComponent 待跳转页面Component
@param actionPush 继续执行跳转动作函数
XGNavigation.addPushPageInterceptor((targetPageComponent,actionPush)=>{
const {needLogin} = targetPageComponent.xgNavigationBarOptions || {};
if (needLogin && !userMobx.phone){
setTimeout(()=>{
actionPush();
},1000);
return false;
}
return true;
});
10.getRouteStack()
作用:获取整个路由栈信息
返回为一个route数组:
[{
pagePath: 'TMMarketTabPage',
pageType: 'NativeTabPage',
uniqueId: 'xxxxx', //唯一id
index: 0,
tabs: [{...}, {...},数据结构同下]
},
{
pagePath: 'TMMarketTabPage',
pageType: 'JSPage',
uniqueId: 'xxxxx',
index: 1,
},
{
pagePath: 'TMMarketTabPage',
pageType: 'NativePage',
uniqueId: 'xxxxx',
index: 2,
}]
10.push(pageConfig, animated)
作用:push进入下一个页面(原生或者ios),一般情况下只需要填下pagePath,剩下的参数会自动补全
@param pageConfig Object Required
.pageType String.页面类型:默认是JSPage,目前仅支持(JSPage,NativePage,NativeTabPage)
.transitionsConfig String.转场动画配置:默认是FromBottom,目前仅支持(FromRight,FromBottom,FromTop)
.pagePath String.页面路径(当pageType为JSPage,NativePage时需要需要指定页面初始化参数,代表js中页面的文件路径、或ios中viewcontroller的class名称、或android中active的class名称)
pagePath支持Object{ios: 'DemoViewController',android:'DemoActivety'}
.params Object.页面初始化参数,可为空(当pageType为JSPage,NativePage时需要需要指定页面初始化参数)
.tabConfigs Tab配置(当且仅当pageType===NativeTabPage)
.selectedIndex 默认选中的tab栏(可选)
.tabCount 多少个tab(__ANDROID__)
.tintColor 选中的Icon和title的颜色,可选项
.unselectedItemTintColor 未选中Icon和title的颜色,可选项
.barTintColor tabbar的颜色,可选项
.barTranslucent: false, // tabbar半透明选项,barTintColor有值则该选项无效,效果不透明 (__IOS__)
.pages Array<itemParams>.tab每一个item的配置
.pageType 数据类型同上(此时不在支持NativeTabPage)
.pagePath 数据类型同上
.params 数据类型同上
.selectTabBarIcon tab选中icon
.unSelectTabBarIcon tab非选中的icon
.tabBarTitle tab对应的title
11.replaceStackTopRoute(pageConfig,animated)
作用:替换栈顶页面
@param pageConfig 新页面配置(具体内容同push函数的pageConfig)
@param animated 是否需要动画
12.pop(animated)
作用:返回上一级页面
@param animated 是否带动画
13.popToRoute(route, animated)
作用:返回到指定页面,每个子页面可使用this.props.route获取自己的route。
@param animated 是否带动画(ANDROID默认动画,不支持animated参数)
14.popToRoot(animated)
作用:返回到路由栈底
@param animated 是否带动画(ANDROID默认动画,不支持animated参数)
15.setTabBarSelectedIndex(route, newIndex)
作用:设置tab页面选中的index
@param route 当前tab子页面的route
@param newIndex 需要选中的下标
注意:如果当前route对应的页面并不存在于Tab容器里,则不执行任何效果
16.isChildTab(route)
作用:判断页面是否处于tab容器中
@param route 当前页面的route
@return {Promise.<bool>} 是否为tab容器里的子页面
17.showLaunchImageOnWindow()
作用:主动添加LaunchImage在window上进行占位显示((如果当前splash已经在展示中,则doNothing)
18.removeLaunchImageFromWindow()
作用:主动从window上移除LaunchImage((如果LaunchImage不存在,则doNothing)
19.allowPopGestureRecognizer(route)
作用:开启关闭侧滑手势(仅支持IOS)
@param route 路由
@param allowPopGesture 侧滑手势是否打开
如果route为tabbar上面的一个子页面,则allowPopGesture对tabbar生效
原生和JS页面跳转,携带函数问题和回到函数问题。
this.props.navigation.push({
pageType: this.props.navigation.pageType.NativePage,
pagePath: {//原生页面的文件名
ios: 'WebController',
android: 'com.xg.jsbridge.WebViewFragment',
},
params: {
url: 'https://www.baidu.com',
jumpCallBack: (obj)=>{
console.warn(obj)
}
},
});
弹框。
首先要全局初始化注入组件。
// 初始化弹框(仅限即支持原声调用、又支持JS调用)
XGNavigation.initializeAlert([
AcquireCouponsAlert
]);
组件内部要书写,这样方便通过字符串的alertPath映射到组件
static alertPath = 'AcquireCouponsAlert';
放置到当期ViewController的View上,或当前frament上,(ios可以侧滑退出)
this.props.navigation.alert({
alertPath: 'AcquireCouponsAlert',//这个弹框组件所书写的static alertPath
bindRoute: this.props.route,
params:{
//组件props的属性
spuIdList: this.spuList,
type: 'ShopCar',
pickerNewCoupons: ()=>{
//用户在优惠券弹框内选择了新的弹框,刷新优惠券提示语(静默,不loading)
this._getCouponTipInfo(this.totalAmount);
}
}
});
放置到当期NavigationController的View上或window上,或当前Activity上,(ios 不可以侧滑退出)
this.props.navigation.alert({
alertPath: 'AcquireCouponsAlert',//这个弹框组件所书写的static alertPath
bindRoute: this.props.route,
params:{
//组件props的属性
spuIdList: this.spuList,
type: 'ShopCar',
pickerNewCoupons: ()=>{
//用户在优惠券弹框内选择了新的弹框,刷新优惠券提示语(静默,不loading)
this._getCouponTipInfo(this.totalAmount);
}
}
});
导航条配置与页面基础状态管理
为了方便业务层能够快速构建页面,toast/alert/loading能力,不用太多的关注页面加载中、加载失败、加载成功的切换, 或单个组件的加载状态(加载中、加载失败、加载成功),以及导航条最基础的配置。 在初始化基础路由配置以后:
XGNavigation.initializeJSRoutes([
home, //首页v1.1.1
coupons, //优惠券
productList,//商品列表
shopping, //购物车
mine, //我的
debug, //调试工具
cmsPage, //CMS页面
XGAuth, //登录、注册
poi, //poi地址搜索
]);
框架内部会对每一个路由页面的Component进行重写,在Component的原型链中添加toast/alert/loading能力。 具体可以浏览PageDecorator文件源码。
/* -------------toast------------- */
target.prototype.xg_toastShow = function (title, params) {
if (!this.xg_toast) {
return;
}
this.xg_toast.showToast(title, params || {});
};
target.prototype.xg_toastDismiss = function (callBack) {
if (!this.xg_toast) return;
this.xg_toast.dismiss(typeof callBack === 'function' ? callBack : null);
};
target.prototype.xg_isToastShow = function () {
if (!this.xg_toast) return false;
return this.xg_toast.isToastShow();
};
/* -------------loading---------- */
target.prototype.xg_loadingShow = function (msg, params) {
if (!this.xg_loadingHub) return;
this.xg_toastDismiss();
this.xg_loadingHub.loadingShow(msg, params || {});
};
target.prototype.xg_loadingDismiss = function (callBack) {
if (!this.xg_loadingHub) return;
this.xg_loadingHub.dismiss(typeof callBack === 'function' ? callBack : null);
};
target.prototype.xg_isLoadingShow = function () {
if (!this.xg_loadingHub) return false;
return this.xg_loadingHub.isLoadingShow();
};
/* -------------alert---------- */
target.prototype.xg_alertShow = function (params) {
this.xg_alertView && this.xg_alertView.alertShow(params);
};
target.prototype.xg_alertDismiss = function (callBack) {
this.xg_alertView && this.xg_alertView.dismiss(callBack);
};
target.prototype.xg_isAlertShow = function () {
if (!this.xg_alertView) return false;
return this.xg_alertView.isAlertShow();
};
/* -------------XGNavigatorBar------------- */
target.prototype.xg_NavigationBarHiddenLeftItem = function (hidden, callBack) {
//隐藏左边item
if (!this.xg_navigatorBar) return;
this.xg_navigatorBar.hiddenLeftItem(hidden, callBack);
};
target.prototype.xg_NavigationBarHiddenRightItem = function (hidden, callBack) {
//隐藏右边item
if (!this.xg_navigatorBar) return;
this.xg_navigatorBar.hiddenRightItem(hidden, callBack);
};
target.prototype.xg_NavigationBarResetTitle = function (newTitle, callBack) {
//更换title
if (!this.xg_navigatorBar) return;
this.xg_navigatorBar.changeTitle(newTitle, callBack);
};
这样这些组件就有了基础的动态设置导航和loading/alert/toast能力。 其实就是底层重写了组件本身的render函数
const targetRender = ComponentClass.prototype.render;
ComponentClass.prototype.render = function () {
const {renderByPageState} = xgNavigationBarOptions;
let controlParams = null;
if (renderByPageState) {
try {
controlParams = this.xg_getPageStateOptions();
} catch (error) {
console.warn('when you set true, you need implementation xg_getPageStateOptions function to return your page state');
controlParams = {};
}
}
const that = this;
return (<View style={styles.container}>
<XGNavigatorBar {...xgNavigationBarOptions}
leftPressed={()=> (this.xg_NavigationBarLeftPressed || xgNavigationBarDefaultLeftPressed).call(this)}
rightPressed={()=>(this.xg_NavigationBarRightPressed || xgNavigationBarDefaultRightPressed).call(this)}
ref={(bar)=>{this.xg_navigatorBar = bar;}}/>
{
renderByPageState ? renderViewByLoadingState(controlParams, () => {
return targetRender.call(that);
}) : targetRender.call(this)
}
<AlertView ref={(alertView) => {this.xg_alertView = alertView;}}/>
<ToastView ref={(toast) => {this.xg_toast = toast;}}/>
<LoadingHub ref={(loadingHub) => {this.xg_loadingHub = loadingHub;}}/>
</View>);
};
对于页面组件,要求大家书写static xgNavigationBarOptions配置。用于配置基础导航条,路由信息等。。。
如果需要设置页面状态管理
在xgNavigationBarOptions配置中renderByPageState设置为true 组件需要实现xg_getPageStateOptions函数,返回当前想要渲染的页面内容。 例如: 具体可以参考PageState文件实现
/**
* 返回当前页面状态,应该有的状态
* @return object 页面当前应该展示的状态
*/
xg_getPageStateOptions = ()=>{
return {
loadingState: this.state.loadingState,
emptyProps: {
description: `暂无可用的优惠券`,
isScrollViewContainer: true,
isRefresh: this.state.refreshing,
source: EmptyImg,
onRefresh: this._onRefresh,
},
netFailedProps: {
netFailedInfo: this.state.error,
callback: () => {
this.setState({
loadingState: PageLoadingState.loading
},()=>{
this._loadDataFirstPage();
});
}
}
};
};