鸿蒙 卡片页面交互:应用页面跳转(一)
本文介绍了ArkTS卡片开发的三种页面交互方式:router事件用于跳转应用内页面,call事件拉起后台服务,message事件实现消息传递。详细讲解了router事件的实现流程,包括卡片按钮布局、参数传递、UIAbility生命周期处理及目标页面加载。通过示例演示了如何通过不同按钮跳转到指定页面,并对比了三种事件类型的应用场景和实现差异。文章还提供了参数解析、生命周期处理等注意事项,帮助开发者掌
本文同步发表于我的微信公众号,微信搜索 程语新视界 即可关注,每个工作日都有文章更新
在ArkTS卡片开发中,页面交互是最核心的功能之一。用户点击卡片上的按钮,可以跳转到应用内的指定页面、传递消息给应用、甚至拉起后台服务。
-
三种事件类型:router、message、call
-
两种卡片形态:动态卡片(postCardAction)和静态卡片(FormLink)
一、卡片交互
ArkTS卡片提供三种页面交互能力:
| 交互能力 | 说明 |
|---|---|
| 页面跳转 | 卡片跳转到卡片提供方应用的指定UIAbility |
| 拉起进程 | 卡片拉起卡片提供方进程 |
| 消息传递 | 卡片与卡片提供方之间的消息通信 |
卡片形态与对应接口
| 卡片类型 | 交互接口 | 适用场景 |
|---|---|---|
| 动态卡片 | postCardAction |
需要动态交互、数据更新的卡片 |
| 静态卡片 | FormLink |
简单展示、无需动态更新的卡片 |
二、三种事件类型
postCardAction和FormLink均支持以下三种事件类型:
| 事件类型 | 作用 | 典型场景 |
|---|---|---|
| router事件 | 跳转到指定UIAbility | 点击卡片进入应用详情页 |
| call事件 | 拉起UIAbility到后台 | 音乐播放、后台任务 |
| message事件 | 触发onFormEvent回调 | 数据刷新、状态同步 |
2.1 router事件(页面跳转)
作用:跳转到指定UIAbility(页面)
限制:
-
非系统应用仅支持跳转到自己应用内的UIAbility
-
不能跳转到其他应用的页面
典型应用:
-
相机卡片:点击"拍照"按钮进入相机界面
-
天气卡片:点击"详情"进入天气预报页面
-
待办卡片:点击"查看全部"进入待办列表
2.2 call事件(后台拉起)
作用:拉起指定UIAbility到后台
特点:
-
UIAbility在后台运行
-
可通过UIAbility申请后台长时任务
-
适合音乐播放、位置跟踪等场景
2.3 message事件(消息传递)
作用:拉起FormExtensionAbility,触发onFormEvent回调
特点:
-
卡片发送消息给应用
-
应用在
onFormEvent中处理消息 -
适合数据刷新、状态同步等场景
三、示例:卡片跳转到应用页面(router事件)
示例功能:
-
卡片上有两个按钮:"FunA页面"和"FunB页面"
-
点击不同按钮,跳转到应用内不同的页面
-
通过
params传递参数,区分跳转目标
3.1 创建卡片布局
// src/main/ets/widgeteventrouter/pages/WidgetEventRouterCard.ets
@Entry
@Component
struct WidgetEventRouterCard {
build() {
Column() {
// 标题文字
Text($r('app.string.JumpLabel'))
.fontColor('#FFFFFF')
.opacity(0.9)
.fontSize(14)
.margin({ top: '8%', left: '10%' })
// 按钮区域
Row() {
Column() {
// 按钮A:跳转到FunA页面
Button() {
Text($r('app.string.ButtonA_label'))
.fontColor('#45A6F4')
.fontSize(12)
}
.width(120)
.height(32)
.margin({ top: '20%' })
.backgroundColor('#FFFFFF')
.borderRadius(16)
.onClick(() => {
// 发送router事件,携带targetPage=funA
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility', // 目标UIAbility
params: { targetPage: 'funA' } // 自定义参数
});
})
// 按钮B:跳转到FunB页面
Button() {
Text($r('app.string.ButtonB_label'))
.fontColor('#45A6F4')
.fontSize(12)
}
.width(120)
.height(32)
.margin({ top: '8%', bottom: '15vp' })
.backgroundColor('#FFFFFF')
.borderRadius(16)
.onClick(() => {
// 发送router事件,携带targetPage=funB
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { targetPage: 'funB' }
});
})
}
}
.width('100%')
.height('80%')
.justifyContent(FlexAlign.Center)
}
.width('100%')
.height('100%')
.alignItems(HorizontalAlign.Start)
.backgroundImage($r('app.media.CardEvent'))
.backgroundImageSize(ImageSize.Cover)
}
}
说明:
| 字段 | 说明 |
|---|---|
action: 'router' |
指定事件类型为router |
abilityName: 'EntryAbility' |
指定要跳转的UIAbility |
params |
传递自定义参数,用于区分不同按钮 |
3.2 在UIAbility中处理router事件
// src/main/ets/entryability/EntryAbility.ts
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { window } from '@kit.ArkUI';
import { hilog } from '@kit.PerformanceAnalysisKit';
const TAG: string = 'EntryAbility';
const DOMAIN_NUMBER: number = 0xFF00;
export default class EntryAbility extends UIAbility {
private selectPage: string = 'funA'; // 默认页面
private currentWindowStage: window.WindowStage | null = null;
// 1. 首次创建时触发
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN_NUMBER, TAG, `Ability onCreate, ${JSON.stringify(want)}`);
// 解析卡片传递的参数
if (want?.parameters?.params) {
// want.parameters.params 对应 postCardAction() 中的 params
let params: Record<string, Object> = JSON.parse(want.parameters.params as string);
this.selectPage = params.targetPage as string;
hilog.info(DOMAIN_NUMBER, TAG, `onCreate selectPage: ${this.selectPage}`);
}
}
// 2. 如果UIAbility已在后台运行,收到router事件后触发
onNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {
hilog.info(DOMAIN_NUMBER, TAG, `onNewWant Want: ${JSON.stringify(want)}`);
// 解析卡片传递的参数
if (want?.parameters?.params) {
let params: Record<string, Object> = JSON.parse(want.parameters.params as string);
this.selectPage = params.targetPage as string;
hilog.info(DOMAIN_NUMBER, TAG, `onNewWant selectPage: ${this.selectPage}`);
}
// 重新加载页面
if (this.currentWindowStage !== null) {
this.onWindowStageCreate(this.currentWindowStage);
}
}
// 3. 窗口创建时加载对应页面
onWindowStageCreate(windowStage: window.WindowStage): void {
let targetPage: string;
// 根据selectPage的值,选择不同的页面
switch (this.selectPage) {
case 'funA':
targetPage = 'funpages/FunA';
break;
case 'funB':
targetPage = 'funpages/FunB';
break;
default:
targetPage = 'pages/Index';
}
// 保存WindowStage实例
if (this.currentWindowStage === null) {
this.currentWindowStage = windowStage;
}
// 加载目标页面
windowStage.loadContent(targetPage, (err, data) => {
if (err.code) {
hilog.error(DOMAIN_NUMBER, TAG, 'Failed to load the content. Cause: %{public}s',
JSON.stringify(err) ?? '');
return;
}
hilog.info(DOMAIN_NUMBER, TAG, 'Succeeded in loading the content. Data: %{public}s',
JSON.stringify(data) ?? '');
});
}
}
生命周期说明:
| 回调 | 触发时机 |
|---|---|
onCreate |
UIAbility首次创建时触发 |
onNewWant |
UIAbility已在后台运行,收到新请求时触发 |
onWindowStageCreate |
窗口创建时触发,用于加载页面 |
3.3 创建目标页面
FunA.ets
// src/main/ets/funpages/FunA.ets
@Entry
@Component
struct FunA {
build() {
Column() {
// 标题栏
Row() {
Text($r('app.string.ButtonA_label'))
.fontSize(24)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Start)
.margin({
top: 12,
bottom: 11,
right: 24,
left: 24
})
}
.width('100%')
.height(56)
.justifyContent(FlexAlign.Start)
// 空状态图片
Image($r('app.media.pic_empty'))
.width(120)
.height(120)
.margin({ top: 224 })
// 空状态文字
Text($r('app.string.NoContentAvailable'))
.fontSize(14)
.fontColor($r('app.color.text_color'))
.opacity(0.4)
.margin({
top: 8,
bottom: 317,
right: 152,
left: 152
})
}
.width('100%')
.height('100%')
}
}
FunB.ets
// src/main/ets/funpages/FunB.ets
@Entry
@Component
struct FunB {
build() {
Column() {
// 标题栏
Row() {
Text($r('app.string.ButtonB_label'))
.fontSize(24)
.fontWeight(FontWeight.Bold)
.textAlign(TextAlign.Start)
.margin({
top: 12,
bottom: 11,
right: 24,
left: 24
})
}
.width('100%')
.height(56)
.justifyContent(FlexAlign.Start)
// 空状态图片
Image($r('app.media.pic_empty'))
.width(120)
.height(120)
.margin({ top: 224 })
// 空状态文字
Text($r('app.string.NoContentAvailable'))
.fontSize(14)
.fontColor($r('app.color.text_color'))
.opacity(0.4)
.margin({
top: 8,
bottom: 317,
right: 152,
left: 152
})
}
.width('100%')
.height('100%')
}
}
3.4 配置页面路由
在main_pages.json中配置所有页面:
// src/main/resources/base/profile/main_pages.json
{
"src": [
"pages/Index", // 默认主页
"funpages/FunA", // FunA页面
"funpages/FunB" // FunB页面
]
}
3.5 配置资源文件
// src/main/resources/zh_CN/element/string.json
{
"string": [
{
"name": "ButtonA_label",
"value": "FunA页面"
},
{
"name": "ButtonB_label",
"value": "FunB页面"
},
{
"name": "JumpLabel",
"value": "router事件跳转"
},
{
"name": "NoContentAvailable",
"value": "暂无内容"
}
]
}
3.6 运行效果
| 场景 | 操作 | 结果 |
|---|---|---|
| 卡片初始状态 | - | 显示两个按钮:"FunA页面"和"FunB页面" |
| 点击"FunA页面" | 卡片发送router事件 | 应用拉起,跳转到FunA页面 |
| 点击"FunB页面" | 卡片发送router事件 | 应用拉起,跳转到FunB页面 |
四、三种事件对比
4.1 事件类型对比表
| 对比项 | router事件 | call事件 | message事件 |
|---|---|---|---|
| 目标 | UIAbility(前台) | UIAbility(后台) | FormExtensionAbility |
| 拉起方式 | 前台显示 | 后台运行 | 后台运行 |
| 典型场景 | 页面跳转 | 音乐播放 | 数据刷新 |
| 生命周期 | onCreate/onNewWant | onCreate/onNewWant | onFormEvent |
4.2 使用示例对比
// router事件 - 跳转到应用页面
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { page: 'detail' }
});
// call事件 - 后台播放音乐
postCardAction(this, {
action: 'call',
abilityName: 'PlayAbility',
params: { song: 'xxx.mp3' }
});
// message事件 - 刷新卡片数据
postCardAction(this, {
action: 'message',
params: { refresh: true }
});
五、注意事项
5.1 限制
| 限制项 | 说明 |
|---|---|
| 跨应用跳转 | 非系统应用只能跳转到自己应用内的UIAbility |
| 参数传递 | params参数需要通过JSON.parse解析 |
| 静态卡片 | 使用FormLink替代postCardAction |
5.2 参数解析
// 卡片发送时
postCardAction(this, {
action: 'router',
abilityName: 'EntryAbility',
params: { targetPage: 'funA' }
});
// UIAbility接收时
// want.parameters.params 是JSON字符串,需要解析
let params: Record<string, Object> = JSON.parse(want.parameters.params as string);
let targetPage = params.targetPage; // 获取到 'funA'
5.3 生命周期处理
// 两种情况需要处理:
// 1. 首次启动 - onCreate
// 2. 已存在实例 - onNewWant
onCreate(want) {
// 处理首次启动
}
onNewWant(want) {
// 处理后台唤醒
// 需要重新加载页面
}
总结
ArkTS卡片:
-
三种事件类型:
-
router:前台页面跳转 -
call:后台服务拉起 -
message:消息传递
-
-
两种卡片形态:
-
动态卡片:
postCardAction -
静态卡片:
FormLink
-
-
router事件完整流程:
-
卡片:
postCardAction({ action: 'router', abilityName, params }) -
UIAbility:
onCreate/onNewWant解析params -
根据params加载不同页面
-
更多推荐




所有评论(0)