鸿蒙主流路由详解
Navigation
Navigation
更适合于一次开发,多端部署,也是官方主流推荐的一种路由控制方式,但是,使用起来入侵耦合度高,所以,一般会使用HMRouter
,这也是官方主流推荐的路由
路由跳转
第一步-定义路由栈
ets
@Provide('PageInfo') pageInfo: NavPathStack = new NavPathStack()
第二步-定义页面跳转构造函数
统一写在主页面
ets
@Builder
PageMap(name: string) {
if (name === "NavDestinationTitle1") {
pageOneTmp() // 自定义组件
} else if (name === "NavDestinationTitle2") {
pageTwoTmp() // 自定义组件
} else if (name === "NavDestinationTitle3") {
pageThreeTmp() // 自定义组件
}
}
分开写在子页面
这种方法,需要自定义路由表,这也是跨包路由所必须的
路由表配置:
-
在跳转目标模块的配置文件module.json5添加路由表配置:
json{ "module" : { "routerMap": "$profile:route_map" } }
-
添加完路由配置文件地址后,需要在工程resources/base/profile中创建route_map.json文件。添加如下配置信息:
json{ "routerMap": [ { "name": "PageOne", // 子组件名称 "pageSourceFile": "src/main/ets/pages/PageOne.ets", // 子组件地址 "buildFunction": "PageOneBuilder", // 字组件构造函数 "data": { "description" : "this is PageOne" // 描述 } } ] }
-
填写构造函数
ets@Builder export function pageOneTmpBuilder(){ pageOneTmp() }
第三步-进行页面跳转
这里只介绍常用简单的跳转方式
不带参数跳转
ets
// 路由表在主页面
this.pageInfo.pushPathByName(`NavDestinationTitle${index}`, null) // 第一个参数是地址,第二个参数是数据
// 路由表是 router_map.json
this.pageInfo.pushPathByName('pageOneTmp', null) // 第一个参数是地址,第二个参数是数据
带参数跳转
ets
// 路由表在主页面
let loginParam:LoginParam = new LoginParam("张三","男", 18) // LoginParam自定义类型
this.pageInfo.pushPathByName(`NavDestinationTitle${index}`,loginParam) // 第一个参数是地址,第二个参数是数据
// 路由表是 router_map.json
let loginParam:LoginParam = new LoginParam("张三","男", 18) // LoginParam自定义类型
this.pageInfo.pushPathByName(`pageOneTmp`,loginParam) // 第一个参数是地址,第二个参数是数据
参数解析
ets
// 子页面
// 获得所有NavDestination的名称
let params:string[] = this.pageInfos.getAllPathName()
console.log(TAG,'所有页面名称',JSON.stringify(params))
// 通过Index获取参数
let obj = this.pageInfos.getParamByIndex(0) as LoginParam
console.log(TAG,'来源页面参数',JSON.stringify(obj))
// 通过名称获取参数(一般路由栈顶端的就是当前页面,params[params.length-1]可以路由栈栈顶名称)
let params2 = this.pageInfos.getParamByName(params[params.length-1])[0] as LoginParam
console.log(TAG,'来源页面参数',JSON.stringify(params2))
带参返回
ets
// 子页面,可以放在onRead()方法里面接收,也可以放在aboutToAppear()方法里面接收
// 获得所有NavDestination的名称
let params:string[] = this.pageInfos.getAllPathName()
console.log(TAG,'所有页面名称',JSON.stringify(params))
// 通过Index获取参数
let obj = this.pageInfos.getParamByIndex(0) as LoginParam
console.log(TAG,'来源页面参数',JSON.stringify(obj))
// 通过名称获取参数(一般路由栈顶端的就是当前页面,params[params.length-1]可以路由栈栈顶名称)
let params2 = this.pageInfos.getParamByName(params[params.length-1])[0] as LoginParam
console.log(TAG,'来源页面参数',JSON.stringify(params2))
// 带参返回
this.pageInfos.pop(obj,true)
主页面解析子页面参数
ets
// 解析参数
let loginParam:LoginParam = new LoginParam("张三","男", 18) // LoginParam自定义类型
this.pageInfo.pushPathByName(`NavDestinationTitle${index}`,loginParam,(popInfo)=>{
console.log(TAG,`NavDestinationTitle${index}返回信息`,JSON.stringify(popInfo.result))
}) // 第一个参数是地址,第二个参数是数据,第三个处理子页面返回的参数
路由拦截
第一步-定义路由栈
ets
@Provide('PageInfo') pageInfo: NavPathStack = new NavPathStack()
第二步-定义页面跳转构造函数
ets
@Builder
PageMap(name: string) {
if (name === "NavDestinationTitle1") {
pageOneTmp() // 自定义组件
} else if (name === "NavDestinationTitle2") {
pageTwoTmp() // 自定义组件
} else if (name === "NavDestinationTitle3") {
pageThreeTmp() // 自定义组件
}
}
第三步-进行页面跳转并进行拦截
ets
// 解析参数
let loginParam: LoginParam = new LoginParam("张三", "男", 18) // LoginParam自定义类型
this.pageInfo.pushPathByName(`NavDestinationTitle${index}`, loginParam, (popInfo) => {
console.log(TAG, `NavDestinationTitle${index}返回信息`, JSON.stringify(popInfo.result))
}) // 第一个参数是地址,第二个参数是数据,第三个处理子页面返回的参数
// 路由拦截
this.pageInfo.setInterception({
willShow: (from: NavDestinationContext | "navBar", to:
NavDestinationContext | "navBar",
operation: NavigationOperation, animated: boolean) => {
if (typeof to === "string") {
console.log("target page is navigation home page.");
return;
}
// 将跳转到PageTwo的路由重定向到PageOne
let target: NavDestinationContext = to as
NavDestinationContext;
console.log(TAG, '当前要跳转界面', target.pathInfo.name)
if (target.pathInfo.name === 'NavDestinationTitle1') {
target.pathStack.pop();
target.pathStack.pushPathByName('NavDestinationTitle2', null);
}
}
})
生命周期
对比
HmRouter
这种路由方式进行了解耦,不用再去写Build函数,它是基于自定义注解的方式,进行路由跳转,这也是官方推荐的方式
基础配置
第一步-使用ohpm安装依赖
ohpm install @hadss/hmrouter // 路由框架
ohpm install @hadss/hmrouter-transitions // 高阶转场动画库,依赖路由框架(可选)
第二步-拷贝artifacts
到工程目录libs文件
(需要自己创建)
第三步-修改oh-package.json5
(entry
目录切记)
报错的话重新输入路径
{
"dependencies": {
"@hadss/hmrouter": "file: ../libs/HMRouterLibrary-${version}.har",
"@hadss/hmrouter-transitions": "file: ../libs/HMRouterTransitions-${version}.har"
}
}
第四步-修改工程的hvigor/hvigor-config.json
文件
{
"dependencies": {
"@hadss/hmrouter-plugin": "file: ../libs/hadss-hmrouter-plugin-${version}.tgz"
// 使用npm仓版本号
}
}
第五步-在模块中引入路由编译插件,修改 hvigorfile.ts
ets
import { hapTasks } from '@ohos/hvigor-ohos-plugin';
import { hapPlugin } from '@hadss/hmrouter-plugin';
//管理HMRouter这个对象的,根据报的类型修改hapPlugin
export default {
system: hapTasks, /* Built-in plugin of Hvigor. It cannot be modified. */
plugins:[hapPlugin()] /* Custom plugin to extend the functionality of Hvigor. */
}
第六步-可选配置hmrouter_config.json
(自己在工程目录下创建)
插件扫描指定目录下的文件,动态的生成被包装好的页面对象
ets
{
"scanDir": ["src/main/ets/components","src/main/ets/interceptors"],
"saveGeneratedFile": true
}
第七步-工程配置在工程目录下的build-profile.json5
"buildOption": {
"strictMode": {
"caseSensitiveCheck": true,
"useNormalizedOHMUrl": true
}
}
使用
第一步-初始化 onCreate()
在UIAbility或者启动框架AppStartup中初始化路由框架
ets
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
HMRouterMgr.init({
context: this.context
})
}
}
第二步-主界面
自定义主界面样式
ets
/**
* 自定义主界面样式
*/
class NavModifier extends AttributeUpdater<NavigationAttribute> {
initializeModifier(instance: NavigationAttribute): void {
instance.mode(NavigationMode.Stack);
instance.navBarWidth('100%');
instance.hideTitleBar(true);
instance.hideToolBar(true);
}
}
主界面使用
ets
import { HMDefaultGlobalAnimator, HMNavigation } from '@hadss/hmrouter';
import { AttributeUpdater } from '@kit.ArkUI';
@Entry
@Component
struct Index {
modifier: NavModifier = new NavModifier()
build() {
Column() {
HMNavigation({
navigationId:'mainNavigation',
homePageUrl:'PageA', // 设置主页
options:{
standardAnimator:HMDefaultGlobalAnimator.STANDARD_ANIMATOR,
dialogAnimator:HMDefaultGlobalAnimator.DIALOG_ANIMATOR,
modifier:this.modifier // 设置页面风格
}
})
{
Button('点我')
}
}
.height('100%')
.width('100%')
}
}
/**
* 自定义主界面样式
*/
class NavModifier extends AttributeUpdater<NavigationAttribute> {
initializeModifier(instance: NavigationAttribute): void {
instance.mode(NavigationMode.Stack);
instance.navBarWidth('100%');
instance.hideTitleBar(true);
instance.hideToolBar(true);
}
}
第三步-可选配置拦截器
ets
import { HMInterceptor, HMInterceptorAction, HMInterceptorInfo, IHMInterceptor } from "@hadss/hmrouter";
const TAG = '[JumpInfoInterceptor]'
@HMInterceptor({ interceptorName: 'JumpInfoInterceptor', global: true })
export class JumpInfoInterceptor implements IHMInterceptor {
handle(info: HMInterceptorInfo): HMInterceptorAction {
/**
* export interface HMInterceptorInfo {
* srcName: string;
* targetName?: string;
* isSrc?: boolean;
* type: HMActionType;
* routerPathInfo: HMRouterPathInfo;
* routerPathCallback?: HMRouterPathCallback;
* context: UIContext;
* }
* 可以根据自己的需求,配置拦截信息
*/
let connectionInfo: string = info.type === 'push' ? 'jump to' : 'back to';
console.info(TAG,'输出信息为',`${info.srcName} ${connectionInfo} ${info.targetName}`)
return HMInterceptorAction.DO_NEXT;
}
}
第四步-路由跳转
不带拦截器的跳转
ets
import { HMRouter, HMRouterMgr } from '@hadss/hmrouter';
const TAG = '[PageC]'
@HMRouter({pageUrl:'PageC'})
@Component
export struct PageC {
aboutToAppear(): void {
let param = HMRouterMgr.getCurrentParam()
console.log(TAG,'PageC的接收参数为',JSON.stringify(param))
}
build() {
Column({space:20}){
Button('PageC')
.onClick(()=>{
HMRouterMgr.pop({
pageUrl:'PageC',
param:'这是来自于C的数据'
})
})
}
}
}
带拦截器的跳转
ets
import { HMRouter, HMRouterMgr } from "@hadss/hmrouter";
const TAG = '[PageB]'
@HMRouter({pageUrl:'PageB',interceptors:['JumpInfoInterceptor']})
@Component
export struct PageB {
aboutToAppear(): void {
let param = HMRouterMgr.getCurrentParam()
console.log(TAG,'PageB的接收参数为',JSON.stringify(param))
}
build() {
Column(){
Button('PageB==>pop')
.onClick(()=>{
HMRouterMgr.pop({
pageUrl:'PageA',
param:'这是来自于B的数据'
})
})
Button('PageB==>push')
.onClick(()=>{
HMRouterMgr.push({
pageUrl:'PageC',
param:'这是来自于B的数据'
})
})
}
}
}