文档管理中心
我的
您当前正在浏览新版开发者文档中心,目录分类和层级有所调整。点击左侧当前文档分类名称前的“☰”图标,可切换文档分类。 了解新版目录
问题处理与运维开发与测试问题应用框架开发UI框架组件使用NavDestination嵌套使用Tabs,TabContent页面如何跳转至目标页面

NavDestination嵌套使用Tabs,TabContent页面如何跳转至目标页面

问题现象

使用Navigation组件导航,NavDestination组件嵌套使用Tabs组件,TabContent组件内再嵌套使用自定义组件,如何在TabContent的自定义组件中使用NavPathStack方法跳转至目标页面?

背景知识

该问题涉及Navigation组件导航与Tabs两方面内容。

  • 组件导航(Navigation)主要用于实现页面间以及组件内部的页面跳转,支持在不同组件间传递跳转参数,提供灵活的跳转栈操作,从而更便捷地实现对不同页面的访问和复用。
  • NavDestination作为子页面的根容器,用于显示Navigation的内容区。
  • NavPathStack:Navigation导航控制器,其中包含NavDestination页面,以栈的结构管理,称为路由栈。
  • 当页面信息较多时,为了让用户能够聚焦于当前显示的内容,需要对页面内容进行分类,提高页面空间利用率。Tabs组件可以在一个页面内快速实现视图内容的切换,一方面提升查找信息的效率,另一方面精简用户单次获取到的信息量。

解决方案

  1. 在src/main目录下的module.json5配置文件中的module字段里配置"routerMap": "$profile:router_map",并在src/main/resources/base/profile目录下新增router_map.json。router_map.json示例如下:
    收起
    自动换行
    深色代码主题
    复制
    1. {
    2. "routerMap": [
    3. {
    4. "name": "PageTabs",
    5. "pageSourceFile": "src/main/ets/pages/PageTabs.ets",
    6. "buildFunction": "PageTabsBuilder",
    7. "data": {
    8. "description": "this is PageTabs"
    9. }
    10. },
    11. {
    12. "name": "HomePage",
    13. "pageSourceFile": "src/main/ets/pages/HomePage.ets",
    14. "buildFunction": "HomePageBuilder",
    15. "data": {
    16. "description": "this is HomePage"
    17. }
    18. },
    19. {
    20. "name": "MinePage",
    21. "pageSourceFile": "src/main/ets/pages/MinePage.ets",
    22. "buildFunction": "MinePageBuilder",
    23. "data": {
    24. "description": "this is MinePage"
    25. }
    26. },
    27. {
    28. "name": "OrderPage",
    29. "pageSourceFile": "src/main/ets/pages/OrderPage.ets",
    30. "buildFunction": "OrderPageBuilder",
    31. "data": {
    32. "description": "this is OrderPage"
    33. }
    34. }
    35. ]
    36. }
  2. Navigation主页面(Index)页面内容:
    点击文字跳转到“父组件(PageTabs.ets)页面”。
    收起
    自动换行
    深色代码主题
    复制
    1. @Entry
    2. @Component
    3. struct Index {
    4. pathStack: NavPathStack = new NavPathStack();
    5. build() {
    6. Navigation(this.pathStack) {
    7. Column() {
    8. Text(`Navigation主页面`)
    9. .fontSize(30)
    10. .onClick(() => {
    11. this.pathStack.pushPath({ name: 'PageTabs' });
    12. });
    13. }
    14. .justifyContent(FlexAlign.Center)
    15. .width('100%')
    16. .height('100%');
    17. };
    18. }
    19. }
  3. 父组件(PageTabs.ets)页面内容:

    UI架构说明:该页面中,Tabs组件为NavDestination组件的子组件,TabContent组件为Tabs组件的子组件,TabContent内为自定义的组件(HomePage和MinePage)。

    收起
    自动换行
    深色代码主题
    复制
    1. import { MinePage } from './MinePage';
    2. import { HomePage } from './HomePage';
    3. @Builder
    4. export function PageTabsBuilder() {
    5. PageTabs();
    6. }
    7. @Component
    8. struct PageTabs {
    9. @State pathStack: NavPathStack = new NavPathStack();
    10. private tabsController: TabsController = new TabsController();
    11. @State currentIndex: number = 0;
    12. @Builder
    13. tabBarBuilder(title: string, targetIndex: number) {
    14. Column() {
    15. Text(title)
    16. .lineHeight(14)
    17. .textAlign(TextAlign.Center)
    18. .fontSize(20)
    19. .fontWeight(20)
    20. .fontColor(this.currentIndex === targetIndex ? '#007DFF' : '#182431')
    21. .margin({ top: 3 });
    22. }
    23. .background('#F1F3F5')
    24. .width('100%')
    25. .height('100%')
    26. .justifyContent(FlexAlign.Center)
    27. .alignItems(HorizontalAlign.Center);
    28. }
    29. build() {
    30. NavDestination() {
    31. Tabs({
    32. barPosition: BarPosition.End,
    33. index: this.currentIndex,
    34. controller: this.tabsController
    35. }) {
    36. TabContent() {
    37. HomePage(); // 首页内容组件,pathStack由context获取,跳转至其他页面失败
    38. }.tabBar(this.tabBarBuilder('首页', 0));
    39. TabContent() {
    40. MinePage({ pathStack: this.pathStack }); // 我的页面内容组件,pathStack由本页面传入,跳转其他页面成功
    41. }.tabBar(this.tabBarBuilder('我的', 1));
    42. }
    43. .barHeight(76)
    44. .vertical(false)
    45. .scrollable(false)
    46. .onChange((index: number) => {
    47. this.currentIndex = index;
    48. this.tabsController.changeIndex(index);
    49. });
    50. }
    51. .onReady((context: NavDestinationContext) => {
    52. this.pathStack = context.pathStack;
    53. });
    54. }
    55. }
  4. “我的”页面(MinePage.ets)内容,pathStack由父组件传入,跳转至OrderPage页面成功:
    收起
    自动换行
    深色代码主题
    复制
    1. @Builder
    2. export function MinePageBuilder() {
    3. MinePage();
    4. }
    5. @Component
    6. export struct MinePage {
    7. pathStack: NavPathStack = new NavPathStack();
    8. onVisible() {
    9. console.info(`MinePage visible.`);
    10. }
    11. build() {
    12. NavDestination() {
    13. Column() {
    14. Text('我的').fontSize(20);
    15. }
    16. .width('100%')
    17. .height('100%')
    18. .onVisibleAreaChange([0.0, 1.0], (isVisible: boolean, currentRatio: number) => {
    19. if (isVisible && currentRatio >= 1.0) { // 由隐藏至显示时执行下面方法
    20. this.onVisible();
    21. }
    22. })
    23. .onClick(() => {
    24. try {
    25. // pathStack由父组件传入,跳转至订单页面成功
    26. this.pathStack.pushPathByName('OrderPage', null);
    27. } catch (err) {
    28. console.error(`pushPathByName error, ${err}`);
    29. }
    30. });
    31. }
    32. .hideTitleBar(true)
    33. .title('Mine');
    34. }
    35. }
  5. HomePage页面:
    收起
    自动换行
    深色代码主题
    复制
    1. @Builder
    2. export function HomePageBuilder() {
    3. HomePage();
    4. }
    5. @Component
    6. export struct HomePage {
    7. pathStack: NavPathStack = new NavPathStack();
    8. build() {
    9. NavDestination() {
    10. Column() {
    11. Text('首页').fontSize(20);
    12. }
    13. .width('100%')
    14. .height('100%')
    15. .onClick(() => {
    16. try {
    17. this.pathStack.pushPathByName('OrderPage', null);
    18. } catch (err) {
    19. console.error(`pushPathByName error, ${err}`);
    20. }
    21. });
    22. }
    23. .hideTitleBar(true)
    24. .title('Home')
    25. .onReady((context: NavDestinationContext) => {
    26. this.pathStack = context.pathStack;
    27. });
    28. }
    29. }
  6. OrderPage页面:
    收起
    自动换行
    深色代码主题
    复制
    1. @Builder
    2. export function OrderPageBuilder() {
    3. OrderPage();
    4. }
    5. @Component
    6. export struct OrderPage {
    7. pathStack: NavPathStack = new NavPathStack();
    8. build() {
    9. NavDestination() {
    10. Column() {
    11. Text('订单').fontSize(20);
    12. }
    13. .width('100%')
    14. .height('100%');
    15. };
    16. }
    17. }