HarmonyOS鸿蒙Next中应用页面跳转和参数传递怎么实现

HarmonyOS鸿蒙Next中应用页面跳转和参数传递怎么实现 应用需要页面跳转和参数传递:

  • 点击按钮跳转到详情页
  • 携带参数跳转
  • 返回时传递结果
  • 路由拦截和鉴权
5 回复

页面跳转

NavPathStack通过Push相关的接口(如pushPathpushPathByNamepushDestinationpushDestinationByName)去实现页面跳转的功能,主要分为以下三类:

  1. 普通跳转,通过页面的name去跳转,并可以携带param。
this.pageStack.pushPath({ name: "PageOne", param: "PageOne Param" });
this.pageStack.pushPathByName("PageOne", "PageOne Param");
  1. 带返回回调的跳转,跳转时添加onPop回调,能在页面出栈时获取返回信息,并进行处理。
this.pageStack.pushPathByName('PageOne', "PageOne Param", (popInfo) => {
  console.info('Pop page name is: ' + popInfo.info.name + ', result: ' + JSON.stringify(popInfo.result));
});
  1. 带错误码的跳转,跳转结束会触发异步回调,返回错误码信息。
this.pageStack.pushDestination({name: "PageOne", param: "PageOne Param"})
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });
this.pageStack.pushDestinationByName("PageOne", "PageOne Param")
  .catch((error: BusinessError) => {
    console.error(`Push destination failed, error code = ${error.code}, error.message = ${error.message}.`);
  }).then(() => {
    console.info('Push destination succeed.');
  });

页面返回

NavPathStack通过pop相关接口(如poppopToNamepopToIndexclear)去实现页面返回功能。

// 返回到上一页
this.pageStack.pop();
// 返回到上一个PageOne页面
this.pageStack.popToName("PageOne");
// 返回到索引为1的页面
this.pageStack.popToIndex(1);
// 返回到根首页(清除栈中所有页面)
this.pageStack.clear();

参数获取

NavDestination子页第一次创建时会触发onReady回调,可以获取此页面对应的参数。

@Component
struct Page01 {
  pathStack: NavPathStack | undefined = undefined;
  pageParam: string = '';
  build() {
    NavDestination() {
      // ...
    }.title('Page01')
    .onReady((context: NavDestinationContext) => {
      this.pathStack = context.pathStack;
      this.pageParam = context.pathInfo.param as string;
    })
  }
}

NavDestination组件中可以通过设置onResult接口,接收返回时传递的路由参数。

class NavParam {
  desc: string = 'navigation-param'
}
@Component
struct DemoNavDestination {
  // ...
  build() {
    NavDestination() {
      // ...
    }
    .onResult((param: Object) => {
      if (param instanceof NavParam) {
        console.info('TestTag', 'get NavParam, its desc: ' + (param as NavParam).desc);
        return;
      }
      console.info('TestTag', 'param not instance of NavParam');
    })
  }
}

其他业务场景,可以通过主动调用NavPathStack的Get相关接口(如getAllPathNamegetParamByIndexgetParamByNamegetIndexByName)去获取指定页面的参数。

// 获取栈中所有页面name集合
this.pageStack.getAllPathName();
// 获取索引为1的页面参数
this.pageStack.getParamByIndex(1);
// 获取PageOne页面的参数
this.pageStack.getParamByName("PageOne");
// 获取PageOne页面的索引集合
this.pageStack.getIndexByName("PageOne");

路由拦截

NavPathStack提供了setInterception方法,用于设置Navigation页面跳转拦截回调。该方法需要传入一个NavigationInterception对象,该对象包含三个回调函数:

名称 描述
willShow 页面跳转前回调,允许操作栈,在当前跳转生效。
didShow 页面跳转后回调,在该回调中操作栈会在下一次跳转生效。
modeChange Navigation单双栏显示状态发生变更时触发该回调。

开发者可以在willShow回调中通过修改路由栈来实现路由拦截重定向的能力。

this.pageStack.setInterception({
  willShow: (from: NavDestinationContext | "navBar", to: NavDestinationContext | "navBar",
    operation: NavigationOperation, animated: boolean) => {
    if (typeof to === "string") {
      console.info("target page is navigation home page.");
      return;
    }
    // 将跳转到PageTwo的路由重定向到PageOne
    let target: NavDestinationContext = to as NavDestinationContext;
    if (target.pathInfo.name === 'PageTwo') {
      target.pathStack.pop();
      target.pathStack.pushPathByName('PageOne', null);
    }
  }
})

更多关于HarmonyOS鸿蒙Next中应用页面跳转和参数传递怎么实现的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


666

解决方案

1. 基础路由跳转

import { router } from '@kit.ArkUI';

@Entry
@Component
struct HomePage {
  build() {
    Column({ space: 16 }) {
      // ✅ 方式1: pushUrl跳转(可返回)
      Button('查看详情')
        .onClick(() => {
          router.pushUrl({
            url: 'pages/DetailPage'
          });
        })
      
      // ✅ 方式2: replaceUrl跳转(不可返回)
      Button('登录')
        .onClick(() => {
          router.replaceUrl({
            url: 'pages/LoginPage'
          });
        })
      
      // ✅ 方式3: back返回
      Button('返回')
        .onClick(() => {
          router.back();
        })
    }
  }
}

2. 携带参数跳转

// 发送页面
@Component
struct ItemList {
  onItemClick(item: Item): void {
    // ✅ 通过params传递参数
    router.pushUrl({
      url: 'pages/ItemDetailPage',
      params: {
        itemId: item.id,
        itemName: item.name,
        // ✅ 可以传递对象
        itemData: item
      }
    }, router.RouterMode.Standard);
  }
  
  build() {
    List() {
      ForEach(this.items, (item: Item) => {
        ListItem() {
          Text(item.name)
        }
        .onClick(() => {
          this.onItemClick(item);
        })
      })
    }
  }
}

// 接收页面
@Entry
@Component
struct ItemDetailPage {
  @State itemId: number = 0;
  @State itemName: string = '';
  @State itemData: Item | null = null;
  
  aboutToAppear(): void {
    // ✅ 获取路由参数
    const params = router.getParams() as Record<string, Object>;
    
    this.itemId = params.itemId as number;
    this.itemName = params.itemName as string;
    this.itemData = params.itemData as Item;
    
    console.info('接收参数:', this.itemId, this.itemName);
  }
  
  build() {
    Column() {
      Text(`ID: ${this.itemId}`)
      Text(`名称: ${this.itemName}`)
    }
  }
}

3. 返回并传递结果

// 页面A: 打开页面B
@Component
struct PageA {
  @State selectedValue: string = '';
  
  async openSelector(): Promise<void> {
    // ✅ 打开选择器页面
    await router.pushUrl({
      url: 'pages/SelectorPage'
    });
    
    // ✅ 监听返回结果
    router.getParams();  // 获取返回的数据
  }
  
  aboutToAppear(): void {
    // ✅ 页面重新显示时获取结果
    const params = router.getParams() as Record<string, Object>;
    if (params && params.selectedValue) {
      this.selectedValue = params.selectedValue as string;
    }
  }
}

// 页面B: 选择后返回
@Component
struct SelectorPage {
  onSelect(value: string): void {
    // ✅ 返回并携带数据
    router.back({
      url: 'pages/PageA',
      params: {
        selectedValue: value
      }
    });
  }
  
  build() {
    List() {
      ListItem() {
        Text('选项1')
      }
      .onClick(() => {
        this.onSelect('选项1');
      })
    }
  }
}

4. RouterMode模式

// ✅ Standard模式(默认): 每次都创建新实例
router.pushUrl({
  url: 'pages/DetailPage'
}, router.RouterMode.Standard);

// ✅ Single模式: 复用已有实例
router.pushUrl({
  url: 'pages/DetailPage',
  params: { id: 2 }
}, router.RouterMode.Single);
// 如果DetailPage已存在,会复用并更新参数

5. 路由拦截

/**
 * 路由守卫
 */
export class RouterGuard {
  /**
   * 需要登录的页面
   */
  private static authPages: string[] = [
    'pages/ProfilePage',
    'pages/SettingsPage',
    'pages/OrderPage'
  ];
  
  /**
   * 跳转前检查
   */
  static async navigate(url: string, params?: Object): Promise<void> {
    // ✅ 检查是否需要登录
    if (this.authPages.includes(url)) {
      const isLoggedIn = await this.checkLogin();
      
      if (!isLoggedIn) {
        // 未登录,跳转到登录页
        router.pushUrl({
          url: 'pages/LoginPage',
          params: {
            redirect: url,  // 登录后跳转回来
            redirectParams: params
          }
        });
        return;
      }
    }
    
    // 已登录或不需要登录,正常跳转
    router.pushUrl({ url, params });
  }
  
  private static async checkLogin(): Promise<boolean> {
    const token = await AppSettings.getInstance().getUserToken();
    return token !== null && token !== '';
  }
}

// 使用路由守卫
Button('我的订单')
  .onClick(() => {
    RouterGuard.navigate('pages/OrderPage');
  })

6. 路由工具类

/**
 * 路由工具类
 */
export class RouterUtils {
  /**
   * 跳转到详情页
   */
  static goToDetail(id: number): void {
    router.pushUrl({
      url: 'pages/DetailPage',
      params: { id }
    });
  }
  
  /**
   * 跳转到编辑页
   */
  static goToEdit(item: Item): void {
    router.pushUrl({
      url: 'pages/EditPage',
      params: { item: JSON.stringify(item) }  // ✅ 复杂对象转JSON
    });
  }
  
  /**
   * 安全返回(检查是否有上一页)
   */
  static safeBack(): void {
    const length = router.getLength();
    if (length > 1) {
      router.back();
    } else {
      // 没有上一页,跳转到首页
      router.replaceUrl({ url: 'pages/Index' });
    }
  }
  
  /**
   * 清空路由栈并跳转
   */
  static clearAndGo(url: string): void {
    router.clear();  // ✅ 清空路由栈
    router.pushUrl({ url });
  }
  
  /**
   * 获取参数(类型安全)
   */
  static getParams<T>(): T | null {
    const params = router.getParams();
    return params ? params as T : null;
  }
}

// 使用
RouterUtils.goToDetail(123);
RouterUtils.goToEdit(item);
RouterUtils.safeBack();

关键API

1. 路由跳转

方法 说明 是否可返回
pushUrl 跳转到新页面
replaceUrl 替换当前页面
back 返回上一页 -
clear 清空路由栈 -

2. 获取信息

// ✅ 获取路由参数
const params = router.getParams();

// ✅ 获取路由栈长度
const length = router.getLength();

// ✅ 获取当前路由状态
const state = router.getState();
console.info('当前页面:', state.path);
console.info('路由名称:', state.name);

实战案例

案例1: 列表-详情跳转

// 列表页
@Component
struct ItemList {
  @State items: Item[] = [];
  
  build() {
    List() {
      ForEach(this.items, (item: Item) => {
        ListItem() {
          Row() {
            Text(item.name).fontSize(16);
          }
          .width('100%')
          .padding(16)
        }
        .onClick(() => {
          // ✅ 跳转到详情
          router.pushUrl({
            url: 'pages/ItemDetailPage',
            params: { itemId: item.id }
          });
        })
      })
    }
  }
}

// 详情页
@Entry
@Component
struct ItemDetailPage {
  @State item: Item | null = null;
  private itemId: number = 0;
  
  aboutToAppear(): void {
    // ✅ 获取参数
    const params = router.getParams() as Record<string, Object>;
    this.itemId = params.itemId as number;
    
    // 加载详情
    this.loadDetail();
  }
  
  async loadDetail(): Promise<void> {
    this.item = await ItemDao.findById(this.itemId);
  }
  
  build() {
    Column() {
      // 返回按钮
      Row() {
        Image($r('app.media.ic_back'))
          .width(24)
          .height(24)
          .onClick(() => {
            router.back();
          })
      }
      
      if (this.item) {
        Text(this.item.name).fontSize(20);
      }
    }
  }
}

案例2: 登录后跳转回原页面

// 登录页
@Entry
@Component
struct LoginPage {
  private redirectUrl: string = '';
  
  aboutToAppear(): void {
    const params = router.getParams() as Record<string, Object>;
    this.redirectUrl = params?.redirect as string || 'pages/Index';
  }
  
  async onLogin(): Promise<void> {
    // 登录成功
    await login();
    
    // ✅ 跳转回原页面
    router.replaceUrl({
      url: this.redirectUrl
    });
  }
}

最佳实践

1. 参数传递

// ✅ 推荐:传递ID,详情页加载数据
router.pushUrl({
  url: 'pages/DetailPage',
  params: { id: 123 }  // 只传ID
});

// ❌ 不推荐:传递大对象
router.pushUrl({
  url: 'pages/DetailPage',
  params: { item: largeObject }  // 对象太大
});

2. 错误处理

try {
  await router.pushUrl({ url: 'pages/DetailPage' });
} catch (err) {
  console.error('跳转失败:', err);
  promptAction.showToast({ message: '页面不存在' });
}

3. 生命周期

@Entry
@Component
struct MyPage {
  // ✅ 页面首次创建
  aboutToAppear(): void {
    const params = router.getParams();
    // 初始化数据
  }
  
  // ✅ 页面重新显示(从其他页面返回时)
  onPageShow(): void {
    // 刷新数据
    this.refreshData();
  }
  
  // ✅ 页面隐藏(跳转到其他页面时)
  onPageHide(): void {
    // 保存状态
  }
}

常见问题

Q1: 返回时如何传递数据?

使用router.back()的params参数,在上一页通过getParams获取。

Q2: 如何清空路由栈?

使用router.clear()清空,然后pushUrl跳转。

Q3: 如何实现Tab内导航?

使用Navigation组件,而不是router。

总结

路由导航要点:

✅ pushUrl跳转,back返回 ✅ params传递参数 ✅ RouterMode控制实例 ✅ 路由守卫鉴权 ✅ 工具类封装常用跳转

参考资料

在HarmonyOS Next中,页面跳转通过router.pushUrl()实现。参数传递使用router.pushUrl()params选项,参数以键值对形式传递。目标页面通过router.getParams()获取传递的参数。

在HarmonyOS Next中,页面跳转与参数传递主要通过router模块实现,以下是核心实现方式:

1. 基础页面跳转与参数传递

  • 跳转:使用router.pushUrl()方法,指定目标页面的pages路径。
  • 传递参数:通过router.pushUrl()params属性携带键值对参数。
// 从Index页面跳转到Detail页面,并传递id参数
import { router } from '@kit.ArkUI';

router.pushUrl({
  url: 'pages/Detail',
  params: { id: 123 }
})

2. 目标页面接收参数 在目标页面的aboutToAppear()生命周期或使用@State装饰器接收参数:

// Detail.ets
@State id: number = 0;

aboutToAppear() {
  const params = router.getParams() as Record<string, number>;
  this.id = params['id'];
}

3. 返回上一页并传递结果

  • 返回:使用router.back()方法。
  • 传递结果:通过router.back()params属性携带返回数据。
// 从Detail页面返回Index页面,并传递结果
router.back({
  url: 'pages/Index',
  params: { result: 'success' }
});

在Index页面的aboutToAppear()中可通过router.getParams()接收返回参数。

4. 路由拦截与鉴权 通过router.addInterceptor()实现全局路由拦截:

// 在EntryAbility的onWindowStageCreate中设置
import { router } from '@kit.ArkUI';

router.addInterceptor((request: router.RouterRequest) => {
  // 鉴权逻辑:检查用户登录状态
  if (!isLogin && request.url.includes('profile')) {
    // 重定向到登录页
    return false; // 拦截跳转
  }
  return true; // 允许跳转
});

5. 页面跳转模式

  • 标准模式router.RouterMode.Standard(默认),多实例跳转。
  • 单实例模式router.RouterMode.Single,目标页若已存在则返回该实例。
router.pushUrl({
  url: 'pages/Detail',
  params: { id: 123 }
}, router.RouterMode.Single);

关键点

  • 页面路径需在module.json5中配置。
  • 参数传递支持基础类型和对象(需序列化)。
  • 通过router.clear()可清空历史栈。

这种设计支持灵活的页面导航与数据流管理,适用于大多数应用场景。

回到顶部