8导航、页面路由

组件导航路由 文档中心

路由导航路线图 页面生命周期
  • aboutToAppear:在创建自定义组件后,执行其build()函数之前执行(NavDestination创建之前),允许在该方法中改变状态变量,更改将在后续执行build()函数中生效
  • onWillAppear:NavDestination创建后,挂载到组件树之前执行,在该方法中更改状态变量会在当前帧显示生效
  • onAppear:通用生命周期事件,NavDestination组件挂载到组件树时执行
  • onWillShow:NavDestination组件布局显示之前执行,此时页面不可见(应用切换到前台不会触发)
  • onShown:NavDestination组件布局显示之后执行,此时页面已完成布局
  • onActive: NavDestination处于激活态(处于栈顶可操作,且上层无特殊组件遮挡)触发
  • onWillHide:NavDestination组件触发隐藏之前执行(应用切换到后台不会触发)
  • onInactive: NavDestination组件处于非激活态(处于非栈顶不可操作,或处于栈顶时上层有特殊组件遮挡)触发
  • onHidden:NavDestination组件触发隐藏后执行(非栈顶页面push进栈,栈顶页面pop出栈或应用切换到后台)
  • onWillDisappear:NavDestination组件即将销毁之前执行,如果有转场动画,会在动画前触发(栈顶页面pop出栈)
  • onDisappear:通用生命周期事件,NavDestination组件从组件树上卸载销毁时执行
  • aboutToDisappear:自定义组件析构销毁之前执行,不允许在该方法中改变状态变量

注意toolbarConfigurationmenus 的图标注意路径:'icon': "resources/base/media/ic_public_highlights.svg"./image/ic_public_highlights.svg,涉及到 icon 图图标类的路径都需要这么写

对象名: NavPathStack = new NavPathStack()
Navigation(this.对象名){
//内容....
}
//.size({width: '数字%', height: '数字%'})
.size({width: 数字, height: 数字})
.title('标题栏文字')
.titleMode(NavigationTitleMode.枚举值) //设置标题模式
.subTitle("副标题文字")
.backButtonIcon(图片格式) //设置返回图标
.hideTitleBar(true) //隐藏标签栏,false:不隐藏
.hideToolBar(false) //隐藏工具栏
.hideBackButton(true) //隐藏返回按钮
.mode(NavigationMode.Stack) //强制让 Navigation单栏布局
.toolbarConfiguration([{ //底部工具栏
value: "Save",
'icon': "resources/base/media/ic_public_highlights.svg",
action: () => console.log("Saved!") //点击事件
}])
// 竖屏最多支持显示3个图标,多余的图标会被放入自动生成的更多图标
.menus([ //标题栏右上角的菜单项
{
value: "搜索",
icon: "resources/base/media/ic_public_highlights.svg",
action: () => { //点击事件
console.log("搜索")
}
}
])

**src/main/resources/base/profile**创建 route_map.json 编写

{
"routerMap": [
{
"name": "页面标识", //子页面唯一标识
"pageSourceFile": "src/main/ets/pages/ziyemian/PageOne.ets", //子页面路径
"buildFunction": "函数名", //子页面入口函数,必须以@Builder修饰
"data": { //描述、权限等扩展信息
"description": "this is pageOne"
}
}
]
}

module.json5添加路由:

"routerMap": "$profile:route_map",  //添加路由

数据传递:通过页面标识传递的,所以不局限于一传二,二传三页面,可以在任意子页面接收到数据

//传递单个字符
MKNavPathStack.pushPathByName('子页面标识', 传入的字符变量名);
NavDestination() {
}
.onReady((context: NavDestinationContext) => {
const pathStack = context.pathStack
const deviceIdList = pathStack.getParamByName('子页面标识') as string[]
if (deviceIdList && deviceIdList.length > 0) {
const deviceId = deviceIdList[deviceIdList.length - 1]
this.mqtt_info.serverID = deviceId
console.log("收到 deviceId: " + deviceId)
}
})

//传递多个
export interface DHTInfoParams {
deviceId: string;
deviceName: string;
linkMode: string;
linkstatus: string;
icon: Resource;
}
const params: DHTInfoParams = {
deviceId: item.deviceViewId,
deviceName: item.deviceName,
linkstatus: item.linkstatus,
icon: getIconByType(item.deviceType),
linkMode: item.pipeline,
};
MKNavPathStack.pushPathByName('子页面标识', params)
NavDestination() {
}
.onReady((context: NavDestinationContext) => { //获取主页面传递的参数
const pathStack = context.pathStack
const paramsArray = pathStack.getParamByName('子页面标识') as DHTInfoParams[]
if (paramsArray && paramsArray.length > 0) {
const param = paramsArray[paramsArray.length - 1] // 取栈顶的那个
this.params.deviceId = param.deviceId
this.params.deviceName = param.deviceName
this.params.icon = param.icon
this.params.linkMode = param.linkMode
this.params.linkstatus = param.linkstatus
console.log("收到参数: " + JSON.stringify(this.params))
this.loadMQTTInfoFromDB()
}
})

数据回传

MKNavPathStack.pushPathByName('MQTTInfoView', this.params.deviceId, (info: PopInfo) => {
this.mqtt_id = info.result.toString()
console.log('回传MQTT的ID:', this.mqtt_id)
});

MKNavPathStack.pop(res.data.data.id);

跳转

this.对象名.pushPath({name: '子页面标识'})
this.对象名.pushPathByName('子页面标识', null)

返回回调(物理&按钮)

NavDestination() {
}
.onBackPressed(()=>{
promptAction.openToast({message:"返回了"})
return true
})

替换,不能返回上一页

this.对象名.replacePath({'子页面标识'})
this.对象名.replacePathByName('子页面标识', null)

页面返回

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

页面删除

// 删除栈中name为PageOne的所有页面
this.对象名.removeByName("子页面标识")
// 删除指定索引的页面
this.对象名.removeByIndexes([1,3,5])
// 删除指定id的页面
this.对象名.removeByNavDestinationId("1");

跳转的页面,因为跳转的页面入口必须是 Builder 修饰的全局函数

@Builder
export function 函数名() { //这里的函数名必须和route_map.json中的buildFunction一致
跳转页面入口函数
}
NavDestination() {} //页面展示必须在这个包裹里面才可以展示

路由拦截

老路由(不推荐)文档中心

@Entry
@Component
struct NavigationAPI9 {
build() {
Navigation() {
//router具备跳转能力
NavRouter() {
//跳转组件 - 只能放置一个组件------------------------------1
// 第二个会覆盖第一个
Button('跳转A')
Button('跳转B')
//要跳转的界面-------------------------------------------2
NavDestination() {
NavRouter() {
// 第一个组件就是点击进行跳转的
Image($r('app.media.b'))
.width(100)
NavDestination(){
Text('第三个页面')
}
}
}
}
}
}
}

三层架构三层架构文档中心

commons(公共能力层):提供整个应用共享的基础组件、工具类、公共配置等,如公共UI组件、数据管理、网络请求封装等,通常编译为HAR包或HSP包

features(基础特性层):实现应用的各个功能模块,每个模块相对独立,可单独开发和测试。通常编译为HAR包、HSP包或Feature类型的HAP包

products(产品定制层):针对不同设备形态(如手机、平板等)进行功能和特性集成,是应用的主入口,通常编译为Entry类型的HAP包

三层架构示例代码.zip

寻找包名:\project01\AppScope\app.json5中的 bundleName

  1. 在工程目录下,创建三个文件夹commons、features、products
  2. 实现首页、课程学习、知识地图这三个功能页面,创建feature模块 quickstart、map、learning,选择Shared Library
  3. 创建commons层模块,创建两个模块utils和uicomponents,选择Static Library

具体使用Static Library 还是 **Shared Library **还需要根据实际情况 文档中心

Module类型 包类型 说明
Ability HAP 应用的功能模块,可以独立安装和运行,必须包含一个entry类型的HAP,可选包含一个或多个feature类型的HAP。
Static Library HAR 静态共享包,编译态复用。
- 支持应用内共享,也可以发布后供其他应用使用。
- 作为二方库,发布到OHPM私仓,供公司内部其他应用使用。
- 作为三方库,发布到OHPM中心仓,供其他应用使用。
- 多包(HAP/HSP)引用相同的HAR时,会造成多包间代码和资源的重复拷贝,从而导致应用包膨大。
- 注意:编译HAR时,建议开启混淆能力,保护代码资产。
Shared Library HSP 动态共享包,运行时复用。
- 当前仅支持应用内共享。
- 当多包(HAP/HSP)同时引用同一个共享包时,采用HSP替代HAR,可以避免HAR造成的多包间代码和资源的重复拷贝,从而减小应用包大小。

模块导出,无论是 **Static Library **或 **Shared Library **都是同样的,引用 HSP 资源: 文档中心,HAR 不需要引用因为是复制包,直接使用即可

对应的页面需要导出

@Entry
@Component
export struct SingSongPage {
@State message: string = 'SingSongPage';

build() {
Row() {
Column() {
Text(this.message)
.fontSize($r('app.float.page_text_font_size'))
.fontWeight(FontWeight.Bold)
.onClick(() => {
this.message = 'Welcome';
})
}
.width('100%')
}
.height('100%')
}
}

当前的文件夹新建 index.ets,导出对应模块文件

export *from './SingSongPage'

然后在 features 或 common 根目录下有个 Index.ets 中也需要导出

export { add } from './src/main/ets/utils/Calc';
export * from './src/main/ets/pages'

导入之后在入口 products 还需要导入,

"dependencies": {
"singsong": "file:../../features/SingSong"
}

在products 中使用 router 跳转模块不能使用常规的路径跳转

router.pushUrl({
//@bundle:包名/模块名/路径
url:'@bundle:com.xinzai.myapplication/SingSong/ets/pages/SingSongPage'
})

使用 navigation 跳转

@Entry
@Component
struct NavigationPage {
navPathStack:NavPathStack =new NavPathStack()

build() {
Navigation(this.navPathStack){
Button('跳转')
.onClick(()=>{
this.navPathStack.pushPath({name: 'singsong' })
})
}.height('100%').width('100%')
}
}

src/main/ets/pages/builders/HspBuilder.ets

import { SingSongPage } from 'singsong'

@Builder
function HspBuilder(){
NavDestination(){
SingSongPage()
}
}

src/main/resources/base/profile/route_map.json

{
"routerMap": [
{
"name": "singsong",
"pageSourceFile": "src/main/ets/pages/builders/HspBuilder.ets",
"buildFunction": "HspBuilder",
"data": {
"description": "this is pageOne"
}
}
]
}

封装工具

API封装工具.zip

数据库操作封装.zip

首选项工具封装.zip

MQTT工具封装.zip

加载弹窗动画封装.zip