在这篇文章中,将逐步的介绍,如何通过Navigation进行页面间的切换。

1、页面跳转的准备工作

首先,开发者需要创建一个NavPathStack对象并作为构造入参传给Navigation组件,以实现二者的绑定,后续的路由操作均基于该NavPathStack展开。

// BasicNavigation.ets

@Component
struct BasicNavigation {
  stack: NavPathStack = new NavPathStack()

  build() {
    // 将导航控制器NavPathStack 绑定至Navigation中。
    Navigation(this.stack) {
        // Navigation作为路由根容器,可以不显示任何内容
    }
  }
}

此时我们已经构建好了一个Navigation根容器并绑定了导航控制器NavPathStack,接下来我们需要构建显示的页面。

Step1、构建子页面

为每个NavDestination声明对外的实例化方法,如代码中的PageOneBuilder,执行该方法会创建一个BasicNavDestination的自定义组件,该组件就是一个Navigation的子页面。

// BasicNavDest.ets

// 组件实例化方法,该方法会创建BasicNavDestination自定义组件作为Navigation的页面
@Builder
export function PageOneBuilder() {
  BasicNavDestination({
    name: 'pageOne'
  });
}

// NavDestination组件
@Component
struct BasicNavDestination {
  name: string = 'NA'

  build() {
    NavDestination() {
        // 页面中的内容
    }
  }
}

Step2、配置Navigation路由表

将步骤一中写好的实例化方法与它的name(开发者自定义)写在路由表的配置文件中(entry/src/main/resources/base/profile/route_map.json开发者自行创建)。

// entry/src/main/resources/base/profile/route_map.json
{
  "routerMap": [
    {
      "name": "basicPageOne", // 路由页面的唯一标识符
      "pageSourceFile": "src/main/ets/pages/BasicFeature/BasicNavDest.ets", // 源码所在地址
      "buildFunction": "PageOneBuilder", // 页面的实例化方法名称
    },
  ]
}

Step3、使能Navigation路由表

将步骤二中创建的route_map.json配置为系统路由表。开发者需要在当前模块的module.json5中,为“module”的内容新增一个配置项,例如:

{
  "module": {
    "name": "entry",
    "type": "entry",
    "description": "$string:module_desc",
    "mainElement": "EntryAbility",
    "deviceTypes": [
      "phone"
    ],
    "pages": "$profile:main_pages",
    "routerMap": "$profile:route_map", // 新增这一行,使能路由表
    "abilities": [...]
  }
}

2、NavPathStack的获取

Navigation根容器和子页面以及路由表配置完成后,即可通过调用NavPathStack的api来实现页面之间的跳转。以下通过按钮点击来触发路由操作:

Button('跳转到basicPageOne')
  .width(330)
  .margin(7)
  .onClick(() => {
    this.stack.pushPath({name: 'basicPageOne'})
  })

对于没有分栏诉求的应用,推荐将Navigation的导航栏NavBar隐藏,基于NavDestination组件进行所有页面功能的开发,例如:

// BasicNavigation.ets

@Component
struct BasicNavigation {
  stack: NavPathStack = new NavPathStack()

  aboutToAppear(): void {
    // 2.将basicPageOne作为Navigation的首页显示
    this.stack.pushPath({name: 'basicPageOne'})
  }

  build() {
    Navigation(this.stack) {
        // Navigation作为路由根容器,可以不显示任何内容
    }
    // 1. 将Navigation导航栏NavBar进行隐藏
    .hideNavBar(true)
  }
}

这样一来,所有的操作均会基于NavDestination组件展开,开发者可以将导航控制器对象NavPathStack存在全局的AppStorage中,方便后续在其他NavDestination中的路由控制:

// BasicNavigation.ets

@Component
struct BasicNavigation {
  stack: NavPathStack = new NavPathStack()

  aboutToAppear(): void {
    // 1.将当前导航控制器对象存储至AppStorage中,可以在同应用内的任意地方获取
    AppStorage.setOrCreate<NavPathStack>('basicNavigationStack', this.stack)
    this.stack.pushPath({name: 'basicPageOne'})
  }

  build() {
    Navigation(this.stack) {
       // Navigation作为路由根容器,可以不显示任何内容
    }
    .hideNavBar(true)
  }
}
// BasicNavDest.ets

@Component
struct BasicNavDestination {
  name: string = 'NA'
  // 2.在Navdestination中获取导航控制器
  stack: NavPathStack = AppStorage.get<NavPathStack>('basicNavigationStack')!

  build() {
    NavDestination() {
        // 页面内容 
    }   
  }
}

此外,还有其他的获取NavPathStack的方式,参见系列后续章节。

3、路由操作方法

navigation框架有三种主要的路由操作:push、pop、replace,下文会分别介绍。

3.1 Push

push操作用以创建一个新的页面视图。主要分为两种,带有异步返回结果的pushDestination和不带返回结果的pushPath。

如果push过程发生了错误,pushPath会跳转到一个空白的页面,pushDestination则会将该错误携带错误码返回给开发者。相应的,如果跳转成功,pushDestination会将成功的结果返回给开发者。示例如下:

// BasicNavDest.ets

Button('pushDestination跳转basicPageOne')
  .width(330)
  .margin(7)
  .onClick(() => {
    // pushDestination会带有异步结果返回
    this.stack.pushDestination({name: 'basicPageOne'})
      .then(() => {
        // .then分支表明本次跳转成功,没有发生错误
        console.log('AceNavigation', 'pushDestination跳转basicPageOne', 'success!')
      })
      .catch((err: Object) => {
        // .catch分支表明本次跳转失败,错误信息包含在入参err中
        console.log('AceNavigation', 'pushDestination跳转basicPageOne', 'failed!')
        console.log('AceNavigation', '-- err info: ' + JSON.stringify(err))
      })
  })
Button('pushPath跳转basicPageOne')
  .width(330)
  .margin(7)
  .onClick(() => {
    // pushPath不带有返回结果
    this.stack.pushPath({name: 'basicPageOne'})
  })

除了是否返回结果外,pushPath与pushDestination在用法上没有区别。开发者还可以通过传入NavigationOptions参数来控制本次push的行为,例如,实现一个单实例跳转、无动画跳转:

// BasicNavDest.ets

Button('单实例、无动画跳转basicPageOne')
  .width(330)
  .margin(7)
  .onClick(() => {
    // 指定launchMode为MOVE_TO_TOP_SINGLETON,会复用Index最大的同名页面;指定animated为false则会禁用本次跳转的动画。
    this.stack.pushPath({name: 'basicPageOne'}, {launchMode: LaunchMode.MOVE_TO_TOP_SINGLETON, animated: false})
  })

3.2 Pop

pop操作用以删除Navigation导航栈顶页面,可以传入参数来控制是否禁用动画。例如:

// BasicNavDest.ets

Button('Pop有动画pop')
  .width(330)
  .margin(7)
  .onClick(() => {
    // 接口无参数传递时默认有动画
    this.stack.pop()
  })
Button('Pop无动画pop')
  .width(330)
  .margin(7)
  .onClick(() => {
    // 传递animated参数为false时,本次操作会禁用动画
    this.stack.pop(false)
  })
  

3.3 Replace

replace操作会用一个新的页面替换当前NavPathStack栈顶页面,如下示例:

// BasicNavDest.ets

Button('replace跳转basicPageOne')
  .width(330)
  .margin(7)
  .onClick(() => {
    // 使用basicPageOne替换当前栈顶页面
    this.stack.replacePath({name: 'basicPageOne'})
  })
Button('replace跳转basicPageTwo')
  .width(330)
  .margin(7)
  .onClick(() => {
    // 使用basicPageTwo替换当前栈顶页面。basicPageTwo上文示例中没有创建,请参照basicPageOne自行实现。
    this.stack.replacePath({name: 'basicPageTwo'})
  })

2.1.3章节的动画示例分别如下(push&&pop、replace):

Logo

为武汉地区的开发者提供学习、交流和合作的平台。社区聚集了众多技术爱好者和专业人士,涵盖了多个领域,包括人工智能、大数据、云计算、区块链等。社区定期举办技术分享、培训和活动,为开发者提供更多的学习和交流机会。

更多推荐