直接跳到内容

导航流程

介绍

本节解释一次导航从注册到渲染的完整流程,帮助你快速定位问题出现的位置。

运行流程

  1. EntryAbility 注册所有模块 RouteGraph
  2. NavigationHost 在页面挂载时创建 NavPathStack 并注入到全局服务。
  3. 业务层通过模块级 NavigatornavigateTo / navigateToForResult 发起跳转。
  4. NavigationService 获取路由名称对应的构建器,构建目标页面并入栈。

入口挂载位置

入口页面负责挂载 NavigationHost,让全局导航栈生效。

ts
import { NavigationHost } from "../navigation/NavigationHost";

/**
 * @file 应用首页,挂载全局 NavigationHost
 */
@Entry
@ComponentV2
struct EntryPage {
  /**
   * 渲染根导航容器
   * @returns {void} 无返回值
   */
  build(): void {
    Column() {
      NavigationHost();
    }
  }
}

NavigationHost 负责挂载导航栈并根据路由名构建页面。

ts
import { MainPage } from "main";
import { NAV_PATH_STACK_KEY, RouteBuild, setNavPathStack } from "navigation";

/**
 * @file 挂载全局导航栈
 */
@ComponentV2
export struct NavigationHost {
  /**
   * 全局导航栈
   */
  @Provider(NAV_PATH_STACK_KEY)
  navPathStack: NavPathStack = new NavPathStack();

  /**
   * 初始化导航栈
   * @returns {void} 无返回值
   */
  aboutToAppear(): void {
    setNavPathStack(this.navPathStack);
  }

  /**
   * 路由构建器映射
   * @param {string} name - 路由名称
   * @returns {void} 无返回值
   */
  @Builder
  PagesMap(name: string): void {
    const builder = RouteBuild.getBuilder(name);
    if (builder) {
      builder.builder(); // 根据路由名渲染目标页
    }
  }

  /**
   * 渲染根导航容器
   * @returns {void} 无返回值
   */
  build(): void {
    Navigation(this.navPathStack) {
      MainPage();
    }
    .hideTitleBar(true)
    .mode(NavigationMode.Stack)
    .navDestination(this.PagesMap);
  }
}

业务层触发跳转

方式一:使用模块级 Navigator(推荐)

ts
import { BaseViewModel } from "base";
import { DemoNavigator } from "navigation";
import type { DemoResult } from "navigation/src/main/ets/demo/DemoResult";

/**
 * @file 导航触发示例 ViewModel
 */
@ObservedV2
export default class DemoNavigationViewModel extends BaseViewModel {
  /**
   * 跳转到带参页面
   * @returns {void} 无返回值
   */
  toWithArgs(): void {
    DemoNavigator.toNavigationWithArgs(1, $r("app.string.demo_goods_name"));
  }

  /**
   * 跳转到结果回传页面
   * @returns {void} 无返回值
   */
  toResultPage(): void {
    DemoNavigator.toNavigationResult()
      .then((result?: DemoResult): void => {
        if (result) {
          console.info("[Navigation] result title=", result.title);
        }
      });
  }
}

方式二:直接使用 NavigationService

ts
import { BaseViewModel } from "base";
import { navigateTo, navigateToForResult } from "navigation";
import { DemoRoutes } from "navigation/src/main/ets/demo/DemoRoutes";
import type { DemoGoodsParam } from "navigation/src/main/ets/demo/DemoParam";
import type { DemoResult } from "navigation/src/main/ets/demo/DemoResult";

/**
 * @file 直接调用导航服务示例 ViewModel
 */
@ObservedV2
export default class DemoNavigationViewModel extends BaseViewModel {
  /**
   * 直接跳转(带参)
   * @returns {void} 无返回值
   */
  toWithArgs(): void {
    const params: DemoGoodsParam = {
      goodsId: 1,
      goodsName: $r("app.string.demo_goods_name")
    };
    navigateTo(DemoRoutes.NavigationWithArgs, params);
  }

  /**
   * 跳转并等待回传结果
   * @returns {void} 无返回值
   */
  toResultPage(): void {
    navigateToForResult<DemoResult>(DemoRoutes.NavigationResult)
        .then((result: DemoResult | undefined) => {
          if (result) {
            console.info("[Navigation] result desc=", result.description);
          }
    });
  }
}

常见问题定位

  • 路由跳转无响应:检查 Graph 是否注册、路由名是否一致。
  • 页面白屏:检查 RouteBuild.register 是否传入了正确的 Builder。
  • 无法获取参数:检查是否在目标页使用 getRouteParams 读取。