这篇文档主要介绍了两种路由控制方式:router方式和Navigation方式,并详细阐述了它们的使用场景、优缺点和具体使用方法
1. 路由控制两种方式
- router方式-更适用 用于模块间与模块内页面切换,通过每个页面的url实现模块间解耦
- Naviagtion- 模块内页面跳转时,为了实现更好的转场动效场景不建议使用router该模块,推荐使用Navigation 。
2. Navigtion的使用
2.1. 介绍
- Navigation组件是路由导航的根视图容器,一般作为Page页面的根容器使用,其内部默认包含了标题栏、内容区和工具栏,其中内容区默认首页显示导航内容(Navigation的子组件)或非首页显示(NavDestination的子组件),首页和非首页通过路由进行切换。
- 优点:一次开发,多端部署场景下,使用Navigation在不同设备中会得到不同的视觉体验
- 缺点:使用门槛较高 , Navigation的这种跳转方式耦合度较高,不适合大型的项目解耦开发。后续可以作为入口页的应用
2.2. 使用方法
● 最外层Navigation
● 有一个控制跳转的对象NavPathStack(需要new)
● 绑定到Navgation上面
● 需要传导到下方的每一层组件,使用这个对象进行跳转和替换
● 子组件(页面)放置到NavDestintion中
● Navigation组件需要配置.navDestion属性(builder)
import { promptAction, PromptAction } from '@kit.ArkUI'
@Entry
@Component
struct NavigationCase2 {
@Provide
stackPath: NavPathStack = new NavPathStack() // 声明一个pathStack对象
@Styles
gridStyle () {
.height(100)
.borderRadius(10)
.backgroundColor(Color.Red)
.margin(10)
}
@Builder
getPageContent (name: string) {
if(name === "friend") {
// 渲染朋友圈组件
Friend()
}
else if(name === "my") {
// 渲染朋友圈组件
My()
}
else if(name === "connect") {
// 渲染朋友圈组件
Connect()
}
else if(name === "chat") {
// 渲染朋友圈组件
Chat()
}
}
build() {
// 绑定关系
Navigation(this.stackPath) {
// 四个导航 导航不同的页面
// 朋友圈 我的 联系人 聊天
GridRow ({ columns: 2 }) {
GridCol() {
Text("朋友圈")
.fontColor(Color.White)
}
.gridStyle()
.onClick(() => {
// this.stackPath.pushPath({
// name: 'friend'
// })
this.stackPath.pushPathByName("friend", null)
})
GridCol() {
Text("我的")
.fontColor(Color.White)
} .gridStyle()
.onClick(() => {
this.stackPath.pushPathByName("my", null)
})
GridCol() {
Text("联系人")
.fontColor(Color.White)
} .gridStyle()
.onClick(() => {
this.stackPath.pushPathByName("connect", null)
})
GridCol() {
Text("聊天")
.fontColor(Color.White)
} .gridStyle()
.onClick(() => {
this.stackPath.pushPathByName("chat", null)
})
}
}
.title("微信主页")
.titleMode(NavigationTitleMode.Mini)
.navDestination(this.getPageContent)
}
}
@Component
struct Friend {
@Consume
stackPath: NavPathStack
build() {
NavDestination() {
Text("朋友圈组件")
Button("到我的").onClick((event: ClickEvent) => {
// this.stackPath.pushPathByName("my", null)
this.stackPath.replacePathByName("my", null)
})
}
.title("朋友圈")
}
}
@Component
struct My {
build() {
NavDestination() {
Text("我的")
}
.title("我的")
}
}
@Component
struct Connect {
build() {
NavDestination() {
Text("联系人")
}
.title("联系人")
}
}
@Component
struct Chat {
build() {
NavDestination() {
Text("聊天")
}
.title("聊天")
}
}
import { RouterBuilder } from './builders'
@Entry
@Component
struct NavigationPathCase {
@Provide
stackPath: NavPathStack = new NavPathStack() // 实例化一个对象绑定到Navigation
@State
list: WeChatItem[] = [{
title: '朋友圈',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
isDivider: true,
toName: 'friend'
},
{
title: '视频号',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
toName: 'video'
}, {
title: '直播',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
isDivider: true,
toName: 'live'
}
, {
title: '扫一扫',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
toName: 'scan'
}, {
title: '听一听',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
isDivider: true,
toName: 'listen'
}
, {
title: '看一看',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
toName: 'look'
}, {
title: '搜一搜',
icon: $r("sys.media.ohos_ic_public_arrow_right"),
isDivider: true,
toName: 'search'
}]
@Builder
getNavBarMenu() {
Column() {
ForEach(this.list, (item: WeChatItem) => {
Row() {
Text(item.title)
Image(item.icon)
.width(30)
.aspectRatio(1)
.fillColor("#c6c6c6")
}
.padding({
left: 20,
right: 20
})
.margin({
bottom: item.isDivider ? 10 : 0
})
.border({
color: "#eaeaea",
width: {
bottom: 1
}
})
.onClick(() => {
// 完成跳转
this.stackPath.pushPathByName(item.toName, null)
// item.toName
})
// .stateStyles({
// normal: {
// .backgroundColor(Color.White)
// },
// pressed: {
// .backgroundColor(Color.Blue)
// }
// })
.height(50)
.backgroundColor(Color.White)
.width("100%")
.justifyContent(FlexAlign.SpaceBetween)
})
}
.width("100%")
}
build() {
Navigation(this.stackPath) {
this.getNavBarMenu() // 获取导航结构
}
.title("")
.titleMode(NavigationTitleMode.Mini)
.height('100%')
.width('100%')
.backgroundColor("#eaeaea")
.navDestination(RouterBuilder)
}
}
class WeChatItem {
title: string = ""
icon: ResourceStr = ""
isDivider?: boolean
toName?: string
}
- 实现公共的路由 创建一个RouterBuilder 构造器
import Friend from '../components/Friend'
import Listen from '../components/Listen'
import Live from '../components/SearchPage'
import LivePage from '../components/LivePage'
import Look from '../components/Look'
import Scan from '../components/Scan'
import VideoPage from '../components/VideoPage'
import SearchPage from '../components/SearchPage'
@Builder
export function RouterBuilder(name: string) {
if (name === "friend") {
Friend()
} else if (name === "live") {
LivePage()
} else if (name === "video") {
VideoPage()
} else if (name === "look") {
Look()
} else if (name === "search") {
SearchPage()
} else if (name === "listen") {
Listen()
} else if (name === "scan") {
Scan()
}
}
- 以其中一个 Friend组件的示例
import { CommonParams } from '../viewmodels'
@Component
struct Friend {
@Consume
stackPath: NavPathStack
build() {
NavDestination() {
Text("朋友圈")
Button("去搜一搜")
.onClick(() => {
let params: CommonParams = {
id: 1,
name: '张三'
}
this.stackPath.pushPath({
name: 'search',
param: params
})
// this.stackPath.replacePath({
// name: 'search'
// })
})
}
.onWillAppear(() => {
console.log("friend_onWillAppear")
})
.onAppear(() => {
console.log("friend_onAppear")
})
.onWillShow(() => {
console.log("friend_onWillShow")
})
.onShown(() => {
console.log("friend_onShown")
})
.onWillHide(() => {
console.log("friend_onWillHide")
})
.onHidden(() => {
console.log("friend_onHidden")
})
.onWillDisappear(() => {
console.log("friend_onWillDisappear")
})
.onDisAppear(() => {
console.log("friend_onDisAppear")
})
.title("朋友圈")
}
}
export default Friend
- 如果需要接受参数,以SearchPage组件为例子,接收参数的示例
import { CommonParams } from '../viewmodels'
@Component
struct SearchPage {
@Consume
stackPath: NavPathStack
aboutToAppear(): void {
const params = this.stackPath.getParamByName("search") as CommonParams[]
AlertDialog.show({
message: JSON.stringify(params[0].name)
})
}
build() {
NavDestination() {
Text("搜索")
Button("返回")
.onClick(() => {
this.stackPath.pop() // 返回
})
}
.title("搜索")
}
}
export default SearchPage
3. router的使用
3.1. 介绍
- router的使用都是基于Entry修饰的组件,都是基于resources/base/profile/main-page.json中的路由配置来跳转的
- 优点:Router模块通过不同的url地址,可以方便地进行页面路由,轻松地访问不同的页面
3.2. 使用方法
router提供下列的几个方法
● pushUrl -压栈
● replaceUrl-替换页面栈
● back-返回
● clear-清空之前页面栈
● getParams-获取参数
● getState-获取当前路由状态
● getLength-获取当前所有的路由长度
● 单例模式
● showAlertBeforeBackPage- (返回阻断)
- 关键api pushUrl会在当前页面层级再加一层页面,不管是不是同一个页面,A -> B 相当于当前页面栈中存在两个页面 A和B , 鸿蒙系统最多页面栈为32
// 注意跳转的页面必须是Entry修饰的页面
Button("push跳转")
.onClick(() => {
router.pushUrl({
url: 'pages/03/RouterCase'
})
})
- replaceUrl :会替换当前页面,不管是不是同一个页面,替换之后相当于页面重新执行
Button("replace跳转")
.onClick(() => {
router.replaceUrl({
url: 'pages/03/RouterCase'
})
})
- clear : 清空页面栈中的所有历史页面,仅保留当前页面作为栈顶页面。
router.clear()
- back : 回到上一个页面- 回到上一个页面,上一个页面并不会重新初始化
router.back()
- getParams : 在跳转过程中,可以给指定页面传递参数,在pushUrl和replaceUrl的第二个参数 。back也可以传参数
Button("push跳转")
.onClick(() => {
router.pushUrl({
url: 'pages/03/RouterCase02',
params: {
id: 1
}
})
})
- 在接收页面通过getParams接收参数
AlertDialog.show({ message: (router.getParams() as Params).id?.toString() })
值得注意的是所有的参数 不论传入和传出都是object,我们需要将其断言成我们想要的类型
- getState : 获取当前页面的状态信息
AlertDialog.show({
message: JSON.stringify(router.getState())
})
- getLength :获取当前页面栈的数量
AlertDialog.show({
message: JSON.stringify(router.getLength())
})
- 单例模式
路由默认属于标准模式
push就是一直追加,不管你有没有加载这个页面
单例模式
比如你加载过A 在栈底放着 再去追加时 会把页面从栈底拿出 放到栈顶
- 单例模式不会造成线程的浪费
假设 A-B-C 现在C现在要回到A,此时用push会变成 A-B-C-A, 用replace会变成A-B-A, 可以给pushUrl加上单例模式, 变成 B-C-A, 或者直接用replace变成 B-A, 或者跳转后clear变成 A
router.pushUrl({
url: 'pages/03/RouterCase'
}, router.RouterMode.Single)
- showAlertBeforeBackPage
router.showAlertBeforeBackPage({
message: '确定要退出吗'
})
该方法只需要在返回之前执行一下即可
- 不能获取点击了确定还是取消,由它本身进行处理