ToB企服应用市场:ToB评测及商务社交产业平台

标题: 探索HarmonyOS:一键掌握Router与NavPathStatck的传参和页面回调技巧 [打印本页]

作者: 三尺非寒    时间: 2024-12-21 02:49
标题: 探索HarmonyOS:一键掌握Router与NavPathStatck的传参和页面回调技巧
路由的选择

    HarmonyOS提供两种路由实现的方式,分别是 RouterNavPatchStack。两者使用场景和殊效各有优劣。
    组件适用场景特点备注Router模块间与模块内页面切换通过每个页面的url实现模块间解耦NavPathStack模块内页面切换通过组件级路由统一起由管理   
    如果是单包应用开发,不使用动态包(hsp)举行拆包,只是使用静态包(har)简单的举行模块拆分,那么我保举使用 navPatchStack。
   
    如果像开发 鸿蒙元服务,对单包体积有 2M 的限制,那么我们不得不使用动态包的方式。将相对独立的功能,二级页面等拆分出去,封装成动态包,可避开 dependencies 直接依赖得引用情势。
    此时使用 router 跳转 url 的方式才可跳转到动态包内非直接引用的页面
    NavPatchStatck 如何跳转(传参)及页面回调

    NavPathStack 是配合 Navigation 一起使用的,
Navigation导航组件做统一的页面跳转管理,它提供了一系列属性方法来设置页面的标题栏、工具栏以及菜单栏的各种展示样式。
    如何跳转(传参)及实现页面回调?
                      登录后复制                  
  1. //第一步:定义一个用于传参和实现页面回调的模型
  2. export interface RouterModel {
  3.   params?: Object, // 要传递给跳转页面的参数
  4.   popCallback?: (value: Object | undefined) => void // 用于页面回调
  5. }
复制代码
     
                               登录后复制                  
  1. //第二步,需要在应用的根页面自行维护 navStack 实例,并传递给根节点 Navigation
  2. @Provide('navPathStack') navPathStack: NavPathStack = new NavPathStack()
  3. Navigation(this.pageInfos) {
  4.   Column() {}
  5. }
  6. .title('NavIndex')
  7. .navDestination(this.PageMap)
  8. // 统一管理维护路由跳转
  9. @Builder
  10.   PageMap(name: string, params: RouterModel) {
  11.     if (name === 'pageOne') {
  12.       TestNavPathPage({ // TestNavPathPage 就是要跳转的目标页面
  13.         routerParams: params
  14.       })
  15.     } else {
  16.       // 默认空页面
  17.     }
  18. }
复制代码
     
                               登录后复制                  
  1. /// 任意一个页面获取 navPathStack 调用跳转并传参
  2. @Component
  3. export struct RouterCallbackExample {
  4.   @Consume('navPathStack') navPathStack: NavPathStack;
  5.   // NavPatchStack 方式跳转并获取回调
  6.   navPathStackJump() {
  7.     const routerParams: RouterModel = {
  8.       params: '我是入参 123', //传递到跳转页面的入参
  9.       popCallback: (callbackValue) => {
  10.         // 这里拿到回调结果,注意要判断 callbackValue !== undefine
  11.         // 这里拿到下面目标页面回传的结果 ‘我是回调的结果 345’
  12.       }
  13.     }
  14.    this.navPathStack.pushPathByName('pageOne', routerParams) // 'pageOne' 对应上面 'PageMap' 方法内定义的路径名称常量
  15.   }
  16.   build() {
  17.     Button('跳转').onClick(() => {
  18.         this.navPathStackJump()
  19.     })
  20.   }
  21. }
复制代码
     
                               登录后复制                  
  1. /// 目标页面接收入参、并返回页面回调
  2. @Component
  3. export struct TestNavPathPage {
  4.   @Consume('navPathStack') navPathStack: NavPathStack;
  5.   routerParams?: RouterModel
  6.   @State receiveParams: string = ''
  7.   aboutToAppear(): void {
  8.     // 接收入参,这里拿到上面传入的 ‘我是入参 123’
  9.     let receiveParams = this.routerParams!.params
  10.   }
  11.   build() {
  12.     NavDestination() {
  13.       Button('关闭页面并回调结果').onClick(() => {
  14.         if (this.routerParams?.popCallback !== undefined) {
  15.           this.routerParams.popCallback('我是回调的结果 345 ')
  16.         }
  17.         this.navPathStack.pop()
  18.       })
  19.     }.title('跳转目标页')
  20.   }
  21. }
复制代码
     
             Router 如何跳转(传参)及页面回调

    Router 跳转可支持跳转本包内页面以及动态包大概拆包内的页面,
   
                      登录后复制                  
  1. 1. 本地包内,或者直接依赖的静态包内页面,url 定义为 : pages/Page1
  2. 2. 分包内的页面,url 定义为 :@bundle:com.rex.harmony.atomic.service/featureName/ets/pages/Page2
  3. // com.rex.harmony.atomic.service 是我的应用包名
  4. // featureName 是跳转页面所在的模块名称,对应 module.json5 里面额 name
  5. // ets/pages/Page2 为目标页面在模块内的页面路径,对应 main_pages.json 内的页面路径
复制代码
     
            
                      登录后复制                  
  1. router.pushUrl({ url: '', params: Object })
复制代码
     
            
   

         重点:截止 API11 版本,router 支持传递的 params 传参,不是引用传递,以是在动态包内实际获取到的不是同一个对象,为了实现页面回调,router 我们需要做如下封装:
        
        (在下文扩展中解释单例为什么这么实现)
                      登录后复制                  
  1. import { RouterModel } from './model/RouterModel'
  2. import { router } from '@kit.ArkUI'
  3. /// 基于 router 库封装,为了实现页面回调
  4. export class FastRouter {
  5.   public readonly routerStack: RouterModel[] = []
  6.   /// 跨 hsp 使用这种方式实现单例
  7.   public static instance(): FastRouter {
  8.     const storageKey = 'REX_FAST_ROUTER'
  9.     if (!AppStorage.has(storageKey)) {
  10.       AppStorage.setOrCreate(storageKey, new FastRouter())
  11.     }
  12.     return AppStorage.get<FastRouter>(storageKey)!
  13.   }
  14.   /// 获取路由传递的入参
  15.   public static get getRouterCurrentParams(): RouterModel | undefined {
  16.     const stack = FastRouter.instance().routerStack
  17.     if (stack.length === 0) {
  18.       return undefined
  19.     }
  20.     return stack[stack.length - 1]
  21.   }
  22.   /// push 页面
  23.   public static async push(route: RouterModel): Promise<void> {
  24.     try {
  25.       await router.pushUrl({ url: route.url, params: route.params })
  26.       FastRouter.instance().routerStack.push(route)
  27.     } catch (_) {
  28.       console.log('>>>>')
  29.     }
  30.   }
  31.   /// replace 页面
  32.   public static async replace(route: RouterModel): Promise<void> {
  33.     try {
  34.       await router.replaceUrl({ url: route.url, params: route.params })
  35.       const instance = FastRouter.instance()
  36.       const list = instance.routerStack
  37.       if (list.length > 0) {
  38.         instance.routerStack.splice(instance.routerStack.length - 1, 1, route)
  39.       }
  40.     } catch (_) {
  41.       // 暂无处理
  42.     }
  43.   }
  44.   /// 退出栈顶页面
  45.   public static async pop(animated?: boolean): Promise<void> {
  46.     router.back()
  47.     const routerStack = FastRouter.instance().routerStack
  48.     routerStack.pop()
  49.   }
  50. }
复制代码
     
                                   登录后复制                  
  1. // 跳转到 hsp 包(feature_hsp_page)内的 TestHspHomePage 页面
  2. const routerParams: RouterModel = {
  3.   url: '@bundle:com.rex.harmony.atomic.service/feature_hsp_page/ets/pages/TestHspHomePage',
  4.   params: '我是入参 1488',
  5.   popCallback: (callbackValue) => {
  6.     if (callbackValue !== undefined) {
  7.       //这里获取跳转页的回调数据
  8.       //接收到下文中目标页面的回调结果:‘我是回调的结果 6100 ’
  9.     }
  10.   }
  11. }
  12. FastRouter.push(routerParams)
复制代码
     
                                   登录后复制                  
  1. @Entry
  2. @Component
  3. struct Index {
  4.   routerParams?: RouterModel
  5.   aboutToAppear(): void {
  6.     this.routerParams = FastRouter.getRouterCurrentParams as RouterModel
  7.     let receiveParams = this.routerParams.params //这里接收入参,也就是上面传递的 ‘我是入参 1488’
  8.   }
  9.   build() {
  10.     Button('关闭页面并回调结果').onClick(() => {
  11.       if (this.routerParams?.popCallback !== undefined) {
  12.         this.routerParams.popCallback('我是回调的结果 6100 ')
  13.       }
  14.       FastRouter.pop()
  15.     })
  16.   }
  17. }
复制代码
     
             总结

    NavPatchStackRouter 两种路由方式各有优劣,NavPatchStack 方便统一管理,Router 方便解耦,两者没有任何关联,可以一起使用,也可以单独使用。
    扩展:动态包、静态包的使用差别

    说到动态包(HAR)和静态包(HSP),这里扩展一下两者的区别。
   

    静态包的 module.json5 文件,type 标识为 har
                      登录后复制                  
  1. {
  2.   "module": {
  3.     "name": "静态包模块名称",
  4.     "type": "har",
  5.     "deviceTypes": [
  6.       "default",
  7.       "tablet"
  8.     ]
  9.   }
  10. }
复制代码
     
             静态包的 module.json5 文件,type 标识为 shared
                      登录后复制                  
  1. {
  2.   "module": {
  3.     "name": "动态包模块名称",
  4.     "type": "shared",
  5.     "description": "$string:shared_desc",
  6.     "deviceTypes": [
  7.       "phone",
  8.       "tablet"
  9.     ],
  10.     "deliveryWithInstall": true,
  11.     "installationFree": true,
  12.     "pages": "$profile:main_pages"
  13.   }
  14. }
复制代码
     
             动态包和静态包都可以被直接引用,在 oh-package.json5 内
                      登录后复制                  
  1. {
  2. ...省略
  3.   "dependencies": {
  4.     "@rex/任意名称": "file:../../base/静态包模块名称",
  5.     "@rex/任意名称": "file:../../base/动态包模块名称"
  6.   }
  7. }
复制代码
     
             重点:
   
         存在两种情况,如果harA和harB都依赖harC,单个hap依赖harA、harB,那么只会存在一份harA、harB、harC;如果harA和harB都依赖harC,有两个hap,hapA依赖harA,hapB依赖harB,那么终极会存在一份harA、harB,两份harC;
        
    举个例子:
   
                      登录后复制                  
  1. class SimgleProvider {
  2.       private static _instance?: SimgleProvider
  3.       public static instance(): SimgleProvider {
  4.         if (!SimgleProvider._instance) {
  5.           SimgleProvider._instance = new SimgleProvider()
  6.         }
  7.         return SimgleProvider._instance
  8.       }
  9.     }
复制代码
     
            
         可以简单的总结为:一个应用内,同一个 har 包,如果同时被 har (大概entry)和 hsp 依赖引用,会被拷贝两份。
        
                      登录后复制                  
  1. class SimgleProvider {
  2.   private static _instance?: SimgleProvider
  3.   public static instance(): FastRouter {
  4.     const storageKey = 'SimgleProvider'
  5.     if (!AppStorage.has(storageKey)) {
  6.       AppStorage.setOrCreate(storageKey, new SimgleProvider())
  7.     }
  8.     return AppStorage.get<SimgleProvider>(storageKey)!
  9.   }
  10. }
复制代码
     
            
    上述示例demo已上传,请参考下方链接
   

    附注(Example)

    Demo 示例已上传:
    GitHub: https://github.com/liyufengrex/HarmonyAtomicService
    GitCode: https://gitcode.com/liyufengrex/HarmonyAtomicService
    (基于API11开发,支持NEXT及以上版本运行)已上传可供参考,包罗如下内容:
   
                      登录后复制                  
  1. // 工程目录
  2. ├──entry                                        // ets代码区
  3. │  └──src/main/ets
  4. │       ├──entryability  
  5. │       │  ├──FoldStatusObserver.ets             // 折叠屏幕变化监听
  6. │       │  └──EntryAbility.ets         
  7. │       ├──pages  
  8. │       │  └──MainPage.ets                       // 首页
  9. ├──business                                      // 放置静态包的文件夹(业务模块)
  10. │  ├──feature_home                               // 放置首页Tab里的一些示例页面                 
  11. │  │   └──/src/main/ets/pages      
  12. │  │      ├──HomePage.ets                         //首页的第一个Tab                     
  13. │  │      ├──BuilderNodeExample.ets               //动态节点操作示例         
  14. │  │      ├──CustomDialogExample.ets              //自定义弹窗解耦
  15. │  │      ├──EventBusExample.ets                  //消息通知
  16. │  │      ├──HttpRequestExample.ets               //网络请求示例
  17. │  │      ├──PermissionExample.ets                //使用注解请求权限
  18. │  │      ├──RouterCallbackExample.ets            //使用 NavPathStack 与 Route 两种方式实现页面跳转及回调(HSP、HAR)
  19. │  │      ├──FixFoldUiExample.ets                 //折叠屏适配示例
  20. │  │      ├──ComponentFactoryExample.ets          //组件工厂示例
  21. │  │      ├──AttributeModifierExample.ets         //组件动态属性设置示例
  22. │  │      └──ThrottleExample.ets                  //使用注解防抖
  23. │  ├──feature_setting   
  24. │  │   └──/src/main/ets/pages  
  25. │  │      ├──SettingPages.ets                     //首页的第二个Tab
  26. │  │      └──TestDynamicNavPage.ets               //测试动态路由示例
  27. ├──features                                       //放置动态包的文件夹
  28. │  ├──feature_has_page  
  29. │  │   └──/src/main/ets/pages  
  30. │  │      ├──TestHspNavPathPage.ets               //测试 NavPath 跳转 HSP 内页面
  31. │  │      └──TestHspRouterPage.ets                //测试 Route 跳转 HSP 内页面
  32. ├──base  
  33. │  ├──fast_ui                                     //封装公共UI
  34. │  │   ├──/src/main/ets/compnents  
  35. │  │   │   ├──FoldStatusContainer.ets             // 折叠屏变化响应组件封装
  36. │  │   │   ├──FastLoading.ets                     // loading工具
  37. │  │   │   └──FastToast.ets                       // toast工具
  38. │  │   └──/src/main/ets/styles                    // 公共样式
  39. │  ├──fast_util                                   // 通用工具
  40. │  │   ├──/src/main/ets
  41. │  │      ├──EventBus.ets                         // 消息通知+监听                     
  42. │  │      ├──FastLog.ets                          // 日志打印
  43. │  │      ├──FastNavRouter.ets                    // 用于动态路由
  44. │  │      ├──FastPermission.ets                   // 请求权限注解器
  45. │  │      ├──FastRouter.ets                       // 基于 router 库封装,为了实现页面回调
  46. │  │      ├──FastTool.ets               
  47. │  │      ├──PreferencesUtil.ets                  // 数据持久化工具
  48. │  │      └──ThrottleTool.ets                     // 防抖注解器
  49. │  ├──global_constant  
  50. │  │
  51. ├──entry/src/main/resources                   // 应用资源目录
  52. └──module.json5                               // 添加卡片拓展能力                        
复制代码
     
             补充

    从 API version 12 开始,Navigation支持使用系统路由表的方式举行动态路由。各业务模块(HSP/HAR)中需要独立配置router_map.json文件(可参考上述demo内TestHspNavPathPage.ets文件)。
    具体可参考文档: Navigation系统路由

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4