问题描述
应用需要页面跳转和参数传递:
- 点击按钮跳转到详情页
- 携带参数跳转
- 返回时传递结果
- 路由拦截和鉴权
关键字: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 控制实例 ✅ 路由守卫鉴权 ✅ 工具类封装常用跳转