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

参考资料

相关推荐
小雨下雨的雨7 分钟前
Flutter 框架跨平台鸿蒙开发 —— Flex 控件之响应式弹性布局
flutter·ui·华为·harmonyos·鸿蒙系统
哈__10 分钟前
入门小白到精通,玩转 React Native 鸿蒙跨平台开发:Button 按钮组件与点击事件
react native·react.js·harmonyos
奋斗的小青年!!23 分钟前
OpenHarmony Flutter实战:打造高性能订单确认流程步骤条
flutter·harmonyos·鸿蒙
Georgewu27 分钟前
【HarmonyOS应用开发】鸿蒙碰一碰分享开发源码和流程讲解
harmonyos
行者9639 分钟前
Flutter跨平台骨架屏组件在鸿蒙系统上的实践与优化
flutter·harmonyos·鸿蒙
奋斗的小青年!!43 分钟前
Flutter自定义图表跨平台适配OpenHarmony
flutter·harmonyos·鸿蒙
奋斗的小青年!!1 小时前
Flutter + OpenHarmony:高性能搜索组件深度优化实战解析
flutter·harmonyos·鸿蒙
哈__1 小时前
React Native 鸿蒙跨平台开发:LayoutAnimation 实现鸿蒙端表单元素的动态添加动画
react native·react.js·harmonyos
小雨下雨的雨1 小时前
Flutter 框架跨平台鸿蒙开发 —— ListView 控件之高效列表渲染艺术
flutter·华为·harmonyos
行者962 小时前
Flutter在OpenHarmony平台的文件上传组件深度实践
flutter·harmonyos·鸿蒙