第3篇:手把手教你如何实现对Navigation路由框架的封装!HarmonyOS 鸿蒙Next(鸿蒙0-1开发)

发布于 1周前 作者 yibo5220 来自 鸿蒙OS

第3篇:手把手教你如何实现对Navigation路由框架的封装!HarmonyOS 鸿蒙Next(鸿蒙0-1开发)
<markdown _ngcontent-ffx-c237="" class="markdownPreContainer">

第3篇:手把手教你如何实现对Navigation路由框架的封装!

在上一篇中,我们已经知道了Navigation的基本使用,本篇我们将实现对Navigation进行封装,使得能适配更多项目。

一、从哪里开始入手?

首先,我们先看回去第2篇中跳转页面的逻辑:

  [@Builder](/user/Builder)
  pageMap(name: string, param: object) {
    //TODO-这里最外层是NavDestination
    //这两种效果是一样的
    if (name === 'AboutMePage') {
      AboutMePage()
    } else if (name === 'AboutMe2Page') {
      NavDestination() {
        AboutMe2Page()
      }
      .mode(NavDestinationMode.STANDARD)
      .hideTitleBar(true)
    }
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

我们来变一下:

[@Builder](/user/Builder)
function getAboutMeBuilder(_value: object): void {
  AboutMePage();
}
[@Builder](/user/Builder)
function getAboutMe2Builder(_value: object): void {
  AboutMe2Page();
}

@Builder pageMap(name: string, param: object) { //TODO-这里最外层是NavDestination //这两种效果是一样的 if (name === ‘AboutMePage’) { wrapBuilder(getAboutMeBuilder).builder(param) } else if (name === ‘AboutMe2Page’) { NavDestination() { wrapBuilder(getAboutMe2Builder).builder(param) } .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

效果还不是很明显,那么我们再改变一下:

[@Builder](/user/Builder)
function getAboutMeBuilder(_value: object): void {
  AboutMePage();
}
[@Builder](/user/Builder)
function getAboutMe2Builder(_value: object): void {
  AboutMe2Page();
}

getBuilder(name: string): WrappedBuilder<[object]> { if (name === ‘AboutMePage’) { return wrapBuilder(getAboutMeBuilder) } else /* if (name === ‘AboutMe2Page’)*/ { return wrapBuilder(getAboutMe2Builder) } }

hasNavDest(name: string): boolean { if (name === ‘AboutMePage’) { return true; } else /* if (name === ‘AboutMe2Page’)*/ { return false; } }

@Builder pageMap(name: string, param: object) { if (this.hasNavDest(name)) { this.getBuilder(name).builder(param) } else { NavDestination() { this.getBuilder(name).builder(param) } .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

看!pageMap函数里面已经可以固定了,我们只需要负责getBuilder能够拿到相应的页面即可!而路由的封装原理,也就是基于这个思路来的!

二、动态import

现在大型的APP基本是多模块同步开发的,所以动态路由就变的至关重要了,而动态路由的重点就是动态import ,动态导入可以很好的节省了内存的使用。下面就来介绍如何使用。

1.动态import实现方案介绍

  • 2.我们以动态import本地HAR模块为案例,实现动态import。
  • 3.我们以登录模块作为动态import的实施对象。
  1. 为了方便管理,我们现在根目录新建一个文件夹,命名为:feature,这这个目录下放置各模块,如:登录模块、分享模块等。
  2. 选中feature文件夹,右击->New->Module,选择Static Library,取名为:login
  3. 我们把login模块添加依赖(oh-package.json5文件中)到entry,其中[@module](/user/module)/login 自己随便取,但一定要与下面保持一致;file:相对路径
"dependencies": {
    "[@module](/user/module)/login": "file:../../../feature/login",
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  1. 接着在entrybuild-profile.json5中添加包:
"buildOption": {
    "arkOptions": {
      // TODO:知识点:动态路由中使用了动态import变量表达式的能力,需要在这里配置模块名,和oh-package.json5中dependencies下面配置的模块名相同。
      "runtimeOnly": {
        "sources": [
        ],
        "packages": [
          "[@module](/user/module)/login",
        ]
      }
    }
  },
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  1. 接着在login模块的根目录Index.ets文件中添加一个函数:
export function harInit(pageName: string) {
  //可以自己打印一下
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  1. 接下来,在entry的一个页面中,通过点击按钮来实现导入。
Button('动态导入登录模块')
    .onClick(async () => {
      await import("[@module](/user/module)/login").then((result: ESObject) => {
        // 动态加载模块成功时,通过模块中的harInit接口加载页面
        result.harInit("register"); //然后在harInit函数中进行,动态 registerPage 页面
      }, (error: ESObject) => {
        // 动态加载模块失败时,打印错误日志
      });
    })
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

点击后,会调用5)中的harInit函数,而通过pageName来决定导入哪一个界面,从而实现了动态import。

三、新建一个路由module

  • 1.为了方便管理,我们现在根目录新建一个文件夹,命名为:common,这这个目录下放置常用的的工具类和路由管理类。
  • 2.选中common文件夹,右击->New->Module,选择Static Library,取名为:router
  • 3.然后在所有需要用到路由跳转的module中添加依赖(oh-package.json5文件中),如:entrylogin
"dependencies": {
    "[@common](/user/common)/router": "file:../../../common/router",
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  • 4.根据pageMap函数的情况,我们需要一个能表示一个页面的data数据类,包含了判断name和是否包含NavDestination 的内容,而根据模块动态加载的原因,需要把name分成:moduleNamepageName,因此我们取一个类为:RouterInfo,具体如下;
/*
 * [@Desc](/user/Desc): 每个路由页面的组成部分,为动态import,所以需要先import(moduleName),然后再根据pageName来决定加载那个组件
 * [@Author](/user/Author): qincji
 * [@Date](/user/Date): 2024/6/19
 */
export interface RouterInfo {
  moduleName: string //模块名称
  pageName: string //页面名称
  hasNavDest?: boolean //默认undefined, 而undefined和false表示该组件没有带 :NavDestination。
}
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  • 5.我们再创建一个统一管理需要增加的页面的页面管理类,就取名为:RouterPage,详细代码如下:
/*
 * [@Desc](/user/Desc): 路由页面统一管理页面,所有的页面都应该在这里添加,方便管理和使用!
 * [@Author](/user/Author): qincji
 * [@Date](/user/Date): 2024/6/20
 */
import { RouterInfo } from './RouterInfo';

export class RouterPage { //方便管理 private static infos: Map<string, RouterInfo> = new Map<string, RouterInfo>(); //TODO - 需要注意的是 moduleName 一定需要与 entry中build-profile.json5、oh-package.json5中dependencies导入定义的一致 //moduleName和pageName并没有限制,唯一即可 static readonly LOGIN: RouterInfo = RouterPage.create("@module/login", “login”, true); static readonly REGISTER: RouterInfo = RouterPage.create("@module/login", “register”); static readonly ENTRY_MODULE_NAME: string = @module/entry”; static readonly ABOUT_ME: RouterInfo = RouterPage.create("@module/entry", “about_me”, true); static readonly ABOUT_ME2: RouterInfo = RouterPage.create("@module/entry", “about_me2”);

private static create(moduleName: string, pageName: string, hasNavDest?: boolean): RouterInfo { const path = moduleName + “/” + pageName; let info = RouterPage.infos.get(path); if (info) { return info; } info = { moduleName: moduleName, pageName: pageName, hasNavDest: hasNavDest }; RouterPage.infos.set(path, info); return info; }

public static getInfo(path: string) { return RouterPage.infos.get(path); }

public static getPath(info: RouterInfo) { return info.moduleName + “/” + info.pageName; } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

很简单的代码,相信大家一看就能懂,就是pageMap中参数name是由moduleName + "/" + pageName组成的,而为了方便查找就增加了一个infos管理。

  • 6.接下来是重点了,在一、从哪里开始入手?中最后改造的结果中,我们需要实现getAboutMeBuildergetBuilderhasNavDest 这几个关键的函数。接下里我们一个一个详细来讲解。
  1. 首先我们先定义一个管理类,就叫RouterNav吧。
  2. 在这个类中,我们统一管理所有的类似getAboutMeBuilder[@Builder](/user/Builder)的注册,于是就有了:
import { RouterInfo } from './RouterInfo';
import { RouterPage } from './RouterPage';
export class RouterNav {
  // 管理需要动态导入的模块,key是模块名,value是WrappedBuilder对象,动态调用创建页面的接口
  private static routerMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>();

public static registerPage(info: RouterInfo, builder: WrappedBuilder<[object]>) { RouterNav.routerMap.set(RouterPage.getPath(info), builder); } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  1. 那么我们需要怎么才能把页面进行registerPage呢?我们在login模块中,添加一个页面叫做LoginPage,然后当该类被import 时进行registerPage,详细代码如下:
import { RouterNav, RouterPage } from '[@common](/user/common)/router';
//不需要[@Entry](/user/Entry)
[@Component](/user/Component)
export struct LoginPage {

build() { NavDestination() { Column() { Text(‘这是登录页面, 有NavDestination’).fontSize(35) } .width(‘100%’) .height(‘100%’) } .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) } }

@Builder function getPage(_value: object): void { LoginPage(); } //在import(xxx/LoginPage)是会执行 RouterNav.registerPage(RouterPage.LOGIN, wrapBuilder(getPage)) <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  1. 接着,我们要看在哪里进行import(xxx/LoginPage)呢?答案就是在login模块的根目录Index.ets文件中,具体如下:
import { RouterPage } from '[@common](/user/common)/router/Index';

// 动态import时需要调用的接口,接口名请使用harInit,用于动态加载页面 export function harInit(pageName: string) { switch (pageName) { case RouterPage.LOGIN.pageName: import(’./src/main/ets/pages/LoginPage’); //当import后,就会执行 RouterNav.registerPage(RouterPage.LOGIN, wrapBuilder(getPage)) ,从而添加到路由管理中 break; } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

是不是很熟悉啊!因为我们上面已经见过了,那接下来看如何触发了。

  1. 我们接着在RouterNav改一下:增加push函数,以及routerStack队列。
import { log } from '[@common](/user/common)/utils';
import { RouterInfo } from './RouterInfo';
import { RouterPage } from './RouterPage';

const TAG = ‘RouterNav’;

export class RouterNav { // 管理需要动态导入的模块,key是模块名,value是WrappedBuilder对象,动态调用创建页面的接口 private static routerMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>(); static navPathStack: NavPathStack = new NavPathStack(); // 通过数组实现自定义栈的管理 private static routerStack: Array<RouterInfo> = new Array();

public static async push(info: RouterInfo, parm: object | undefined = undefined, navPath: NavPathInfo = new NavPathInfo(RouterPage.getPath(info), parm)) { const moduleName: string = info.moduleName; const pageName: string = info.pageName; // 动态加载模块是否成功 let isImportSucceed: boolean = false; // entry模块不需要动态加载源码 if (moduleName === RouterPage.ENTRY_MODULE_NAME) { isImportSucceed = true; } else { // TODO:知识点:通过动态import的方式引入模块,在需要进入页面时才加载模块,可以减少主页面的初始化时间及占用的内存 await import(moduleName).then((result: ESObject) => { // 动态加载模块成功时,通过模块中的harInit接口加载页面 result.harInit(pageName); //然后在harInit函数中进行,动态 registerPage 页面 isImportSucceed = true; }, (error: ESObject) => { // 动态加载模块失败时,打印错误日志 log.d(TAG, error) }); } if (isImportSucceed) { RouterNav.routerStack.push(info); if (info.hasNavDest) { RouterNav.navPathStack.pushPath(navPath); } else { RouterNav.navPathStack.pushPath(navPath); } } }

public static registerPage(info: RouterInfo, builder: WrappedBuilder<[object]>) { RouterNav.routerMap.set(RouterPage.getPath(info), builder); } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

其中最重点的就是await import部分代码,当外部调用push时,import(moduleName)会导入模块的Index.ets 文件,然后通过result.harInit调用文件里面的函数!

  1. 接着把navPathStackentryNavigation替换一下变成了:Navigation(RouterNav.navPathStack)
  2. 回到主题,上面6个步骤我们只是getAboutMeBuilder对进行处理,接下来我们对getBuilderhasNavDest 也处理下,这两个很简单,在RouterNav增加两个函数:
  public static getBuilder(name: string): WrappedBuilder<[object]> {
    const builder = RouterNav.routerMap.get(name);
    const meth = builder as WrappedBuilder<[object]>
    return meth;
  }

public static hasNavDest(name: string): boolean { const info = RouterPage.getInfo(name); if (info === undefined) { log.e(TAG, ${name} --&gt; 没有注册路由!) return false; } if (info.hasNavDest === undefined) { return false; } return info.hasNavDest; } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  1. 然后再回到entry变换一下pageMap,如下:
  [@Builder](/user/Builder)
  pageMap(name: string, param: object) {
    if (RouterNav.hasNavDest(name)) {
      RouterNav.getBuilder(name).builder(param);
    } else {
      NavDestination() {
        RouterNav.getBuilder(name).builder(param);
      }
      .mode(NavDestinationMode.STANDARD)
      .hideTitleBar(true)
    }
  }
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  1. 最后,我们实现一下跳转,
Button('登录')
    .onClick(() => {
      RouterNav.push(RouterPage.LOGIN)
    })
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  1. 我们把完整的RouterNav放出来:
/*
 * [@Desc](/user/Desc): navigation路由的管理器,统一封装入栈和出栈等操作!
 * [@Author](/user/Author): qincji
 * [@Date](/user/Date): 2024/6/19
 */
import { log } from '[@common](/user/common)/utils';
import { RouterInfo } from './RouterInfo';
import { RouterPage } from './RouterPage';

const TAG = ‘RouterNav’;

export class RouterNav { // 管理需要动态导入的模块,key是模块名,value是WrappedBuilder对象,动态调用创建页面的接口 private static routerMap: Map<string, WrappedBuilder<[object]>> = new Map<string, WrappedBuilder<[object]>>(); //方便查询 static navPathStack: NavPathStack = new NavPathStack(); // 通过数组实现自定义栈的管理 private static routerStack: Array<RouterInfo> = new Array();

/**

  • 获取组件
  • @param name
  • @returns */ public static getBuilder(name: string): WrappedBuilder<[object]> { const builder = RouterNav.routerMap.get(name); const meth = builder as WrappedBuilder<[object]> return meth; }

/**

  • 判断该组件是否包含:NavDestination
  • @param name
  • @returns */ public static hasNavDest(name: string): boolean { const info = RouterPage.getInfo(name); if (info === undefined) { log.e(TAG, ${name} --&gt; 没有注册路由!) return false; } if (info.hasNavDest === undefined) { return false; } return info.hasNavDest; }

/**

  • 页面跳转
  • @param info
  • @param parm 需要传递给下一个页面的参数
  • @param navPath */ public static async push(info: RouterInfo, parm: object | undefined = undefined, navPath: NavPathInfo = new NavPathInfo(RouterPage.getPath(info), parm)) { const moduleName: string = info.moduleName; const pageName: string = info.pageName; // 动态加载模块是否成功 let isImportSucceed: boolean = false; // entry模块不需要动态加载源码 if (moduleName === RouterPage.ENTRY_MODULE_NAME) { isImportSucceed = true; } else { // TODO:知识点:通过动态import的方式引入模块,在需要进入页面时才加载模块,可以减少主页面的初始化时间及占用的内存 await import(moduleName).then((result: ESObject) => { // 动态加载模块成功时,通过模块中的harInit接口加载页面 result.harInit(pageName); //然后在harInit函数中进行,动态 registerPage 页面 isImportSucceed = true; }, (error: ESObject) => { // 动态加载模块失败时,打印错误日志 log.d(TAG, error) }); } if (isImportSucceed) { RouterNav.routerStack.push(info); if (info.hasNavDest) { RouterNav.navPathStack.pushPath(navPath); } else { RouterNav.navPathStack.pushPath(navPath); } } }

/**

  • 需要带返回结果的方式跳转下个页面
  • @param navPath */ public static async pushCallback(navPath: NavPathInfo) { const info = RouterPage.getInfo(navPath.name); if (info === undefined) { return; } await RouterNav.push(info, undefined, navPath); }

/**

  • 在当前页面打开下一个页面
  • @param info
  • @param parm
  • @param navPath */ public static async replace(info: RouterInfo, parm: object | undefined = undefined, navPath: NavPathInfo = new NavPathInfo(RouterPage.getPath(info), parm)) { const popInfo = RouterNav.routerStack.pop(); if (popInfo !== undefined) { RouterNav.routerMap.delete(RouterPage.getPath(popInfo)); } RouterNav.routerStack.push(info); RouterNav.navPathStack.replacePath(navPath, true); }

/**

  • 返回
  • @param result 返回的结果 */ public static pop(result?: Object) { if (result !== undefined) { RouterNav.navPathStack.pop(result, true) } else { RouterNav.navPathStack.pop(true) } }

/**

  • 注册页面
  • @param info
  • @param builder */ public static registerPage(info: RouterInfo, builder: WrappedBuilder<[object]>) { RouterNav.routerMap.set(RouterPage.getPath(info), builder); } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

四、参数传递和注意事项

  • 1.如果是跳转到entry页面,很好的通过import(moduleName)进行动态加载,最简单的方式的直接预加载:
 aboutToAppear(): void {
    this.initImportEntryPage();
  }

//TODO - 本entry的页面需要实现进行导入,很很费内存,但没有找到更好的动态导入的方案。所以不建议把非必要页面放在entry private initImportEntryPage() { new Promise<void>(async () => { await import(’…/pages/AboutMePage’) await import(’…/pages/AboutMe2Page’) }) } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  • 2.如果entry有很多页面,上面的方式比较耗费内存,也可以改造成功动态导入,只是会麻烦了一点。
  1. 首先,我们在entry增加一个类,实现动态导入:
import { RouterInfo, RouterPage } from '[@common](/user/common)/router/Index';

export class PageLoader { static async loadData(info: RouterInfo) { if (info.pageName === RouterPage.ABOUT_ME.pageName) { await import(’…/pages/AboutMePage’) } else if (info.pageName === RouterPage.ABOUT_ME2.pageName) { await import(’…/pages/AboutMe2Page’) } } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  1. 我们在使用的过程中,先进进行动态导入:
Button('去关于我的页面')
    .onClick(async () => {
      await PageLoader.loadData(RouterPage.ABOUT_ME)
      RouterNav.push(RouterPage.ABOUT_ME)
    })
<button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>
  • 3.上面两者两种各有优缺点,我的建议是看怎么使用:
  1. 如果是只有一个entry的项目的话,把router也放在entry,然后在push里面实现await PageLoader.loadData
  2. 不建议在entry写非必要的页面。
  • 4.如何页面之间如何实现传递参数呢?
  1. 把参数传递到下一页面,不需要回来结果:
 Button('登录--》传些参数看看')
    .onClick(() => {
      const record: Record<string, Object> = {
        'from': 'entry/home',
        'text': this.value,
        'age': 18,
      }
      RouterNav.push(RouterPage.LOGIN, record)
    })

//然后在登录页面获取参数 @Component export struct LoginPage { @State result: string = “”;

build() { NavDestination() { Column() { Text(‘这是登录页面, 有NavDestination’).fontSize(35) Text(接收到的数据:${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.result}).fontSize(35) } .width(‘100%’) .height(‘100%’) } .onReady(cxt => { const record = cxt.pathInfo.param as Record<string, object>; this.result = JSON.stringify(record); }) .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

  1. 把参数传递到下一页面,且需要回来结果:
//entry
Button('登录--》传些参数看看')
    .onClick(() => {
      const record: Record<string, Object> = {
        'from': 'entry/home',
        'text': this.value,
        'age': 18,
      }
      RouterNav.pushCallback({
        name: RouterPage.getPath(RouterPage.LOGIN),
        param: record,
        onPop: async (info: PopInfo) => {
          this.value = JSON.stringify(info);
          //取得回来的参数
          let params = (info.result as Record<string, Object>);
        }
      })
    })

//login @Component export struct LoginPage { @State result: string = “”; build() { NavDestination() { Column() { Text(‘这是登录页面, 有NavDestination’).fontSize(35) Text(接收到的数据:${<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.result}).fontSize(35) Button(‘返回–》给点数据’) .onClick(() => { const record: Record<string, Object> = { ‘from’: ‘login/login’, ‘text’: “登录给你的”, ‘age’: 19, } RouterNav.pop(record)//返回结果,record可以是object }) } .width(‘100%’) .height(‘100%’) } .onReady(cxt => { const record = cxt.pathInfo.param as Record<string, object>; this.result = JSON.stringify(record); }) .mode(NavDestinationMode.STANDARD) .hideTitleBar(true) } } <button style="position: absolute; padding: 4px 8px 0px; cursor: pointer; top: 4px; right: 8px; font-size: 14px;">复制</button>

到这里,所有的内容已经结束了!本章的完整源码已经上传到gitee了:鸿蒙应用0-1开发

</markdown>
14 回复
大佬,gittee下载压缩包后解压后,里面代码例子是空文件夹。
能再上传一份完整代码例子供下载学习吗?

应该有的,是不是路径没对啊。试一下直接:git clone https://gitee.com/qincji/ZeroOneApp.git

本章: entry路径: ZeroOneApp/app/003/entry/src/main/ets/pages/EntryView.ets router路径: ZeroOneApp/common/router/src/main/ets/core/RouterNav.ets

ZeroOneApp/common/router/src/main/ets/core/RouterNav.ets 没有这个文件

beta1已经有系统路由表了,可以使用系统路由表进行简化

升级的好快iiiiing

是的,官方一些demo应该也更新了

看了demo,确实不错,可以单独把路由模块拆分开来。就是使用同样是那么的复杂。

看得不是很明白!我就想问问,简单使用NavPathStack,Navigation,NavDestination
这三个,是不是要做一个[@Builder](/user/Builder)修饰的很多个if做成的路由表?比如一个app有几十个页面就要做几十个if判断?

dp2确实是需要这样做。

发布到用户的 next 版本 是 API version 12 的?

开发beta版本是API 12

NavDestination() { }   不加.navDestination(this.PagesMap) 这个属性就会崩溃,加了就正常,是还有其他什么额外的配置吗

在HarmonyOS鸿蒙Next中,实现对Navigation路由框架的封装,可以通过模块化设计,利用@Builder注解构建页面映射,并动态加载模块以节省内存。封装时需注意API版本差异,如API 10后推荐使用NavPathStack实现路由。封装应支持多显示模式,如单栏、分栏和自适应,并提供丰富的标题栏和工具栏配置。如果问题依旧没法解决,请加我微信,我的微信是itying888。

回到顶部