[鸿蒙2025领航者闯关]HarmonyOS路由跳转

问题描述

应用需要页面跳转和参数传递:

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

关键字:Router页面跳转参数传递路由导航

解决方案

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 控制实例 ✅ 路由守卫鉴权 ✅ 工具类封装常用跳转

参考资料

相关推荐
hh.h.3 小时前
开源鸿蒙生态下Flutter的发展前景分析
flutter·开源·harmonyos
讯方洋哥6 小时前
HarmonyOS应用开发——应用状态
华为·harmonyos
ujainu6 小时前
鸿蒙与Flutter:全场景开发的技术协同与价值
flutter·华为·harmonyos
FrameNotWork6 小时前
HarmonyOS 教学实战:从 0 写一个完整应用(真正能跑、能扩展)
pytorch·华为·harmonyos
Random_index7 小时前
#HarmonyOS篇:鸿蒙开发模板&&三方库axios使用&&跨模块开发交互
harmonyos
游戏技术分享8 小时前
【鸿蒙游戏技术分享 第71期】资质证明文件是否通过
游戏·华为·harmonyos
赵浩生8 小时前
鸿蒙技术干货11:属性动画与转场效果实战
harmonyos
Monkey_249 小时前
鸿蒙开发工具大全
华为·harmonyos
灰灰勇闯IT11 小时前
鸿蒙 5.0 开发入门第二篇:掌握 ArkTS 的 if 分支语句,实现条件逻辑判断
华为·harmonyos