讲路由之前先复习下堆栈的概念
栈的定义 栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素 简单定义: 栈就是一种只允许在表尾进行插入和删除操作的线性表
栈的术语说明 栈顶:允许进行插入和进行删除操作的一段成为栈顶 栈底:表的另一端称为栈底 (第一个元素进入的位置) 压栈:在栈顶位置插入元素的操作叫做压栈,或入栈、进栈 出栈:删除栈顶元素的操作叫做出栈,也叫作弹栈,或者退栈 空栈:不含元素的空表 栈溢出:当栈满的时候,如果再有元素压栈,则发生上溢,当栈空的时候,再出栈则发生下溢
理解栈 我们分别浏览了页面A、页面B、页面C,所以我们将这些页面依次压入栈,即图中打开页面部分 当用户点击后退时,我们需要退回到页面B中去,但是由于页面C在B上方,我们就必须将页面C从栈M中先弹出,放到栈N中,即图中后退部分 但是如果用户突然又想回到页面C去,原理相似的,只需要把栈N中的页面C弹出,重新压入栈M即可 而如果用户在浏览B界面的时候,打开了新的界面D,那么C就无法通过前进后退访问了,所以栈M中压入页面D的同时还需要清空栈N
鸿蒙的路由
鸿蒙系统以其独特的分布式架构和跨设备的统一体验而备受瞩目。在这个系统中,页面路由(Router)机制是连接应用各页面的关键组成部分
1.1. 两种跳转模式
Router模块提供了两种跳转模式,分别是router.pushUrl()和router.replaceUrl()。这两种模式决定了目标页是否会替换当前页。 router.pushUrl(): 目标页不会替换当前页,而是压入页面栈。这样可以保留当前页的状态,并且可以通过返回键或者调用router.back()方法返回到当前页。 router.replaceUrl(): 目标页会替换当前页,并销毁当前页。这样可以释放当前页的资源,并且无法返回到当前页。
说明 创建新页面时,请参考构建第二个页面配置第二个页面的路由。 页面栈的最大容量为32个页面。如果超过这个限制,可以调用router.clear方法清空历史页面栈,释放内存空间。
1.2. 两种实例模式
Standard:多实例模式, 也是默认情况下的跳转模式。目标页面会被添加到页面栈顶,无论栈中是否存在相同url的页面。 Single:单实例模式。 如果目标页面的url已经存在于页面栈中,则会将离栈顶最近的同url页面移动到栈顶,该页面成为新建页。如果目标页面的url在页面栈中不存在同url页面,则按照默认的多实例模式进行跳转。
1.3使用场景
场景一: 有一个主页(Home)和一个详情页(Detail),希望从主页点击一个商品,跳转到详情页。同时,需要保留主页在页面栈中,以便返回时恢复状态。这种场景下,可以使用pushUrl方法,并且使用Standard实例模式(或者省略)。
import { router } from '@kit.ArkUI';
// 在Home页面中
function onJumpClick(): void {
router.pushUrl({
url: 'pages/Detail' // 目标url
}, router.RouterMode.Standard, (err) => {
if (err) {
console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Invoke pushUrl succeeded.');
});
}
场景二 有一个登录页(Login)和一个个人中心页(Profile),希望从登录页成功登录后,跳转到个人中心页。同时,销毁登录页,在返回时直接退出应用。这种场景下,可以使用replaceUrl方法,并且使用Standard实例模式(或者省略)。
import { router } from '@kit.ArkUI';
// 在Login页面中
function onJumpClick(): void {
router.replaceUrl({
url: 'pages/Profile' // 目标url
}, router.RouterMode.Standard, (err) => {
if (err) {
console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Invoke replaceUrl succeeded.');
})
}
// 登录成功,返回到首页
router.replaceUrl({
url: 'pages/shop/ShopIndex'
})
场景三: 有一个设置页(Setting)和一个主题切换页(Theme),希望从设置页点击主题选项,跳转到主题切换页。同时,需要保证每次只有一个主题切换页存在于页面栈中,在返回时直接回到设置页。这种场景下,可以使用pushUrl方法,并且使用Single实例模式。
import { router } from '@kit.ArkUI';
// 在Setting页面中
function onJumpClick(): void {
router.pushUrl({
url: 'pages/Theme' // 目标url
}, router.RouterMode.Single, (err) => {
if (err) {
console.error(`Invoke pushUrl failed, code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Invoke pushUrl succeeded.');
});
}
场景四: 有一个搜索结果列表页(SearchResult)和一个搜索结果详情页(SearchDetail),希望从搜索结果列表页点击某一项结果,跳转到搜索结果详情页。同时,如果该结果已经被查看过,则不需要再新建一个详情页,而是直接跳转到已经存在的详情页。这种场景下,可以使用replaceUrl方法,并且使用Single实例模式。
import { router } from '@kit.ArkUI';
// 在SearchResult页面中
function onJumpClick(): void {
router.replaceUrl({
url: 'pages/SearchDetail' // 目标url
}, router.RouterMode.Single, (err) => {
if (err) {
console.error(`Invoke replaceUrl failed, code is ${err.code}, message is ${err.message}`);
return;
}
console.info('Invoke replaceUrl succeeded.');
})
}
1.4路由传参
在目标页面中,在需要获取参数的位置调用router.getParams方法即可,例如在onPageShow生命周期回调中:
说明 直接使用router可能导致实例不明确的问题,建议使用getUIContext获取UIContext实例,并使用getRouter获取绑定实例的router。
往页面传数据
.onClick(() => {
router.pushUrl({
url: 'pages/ProductDetail',
params: {
prodId: this.productDataModel?.prodId
}
})
})
接受参数
onPageShow(): void {
let params = router.getParams() as string
this.name = params['name']
console.log('name '+this.name)
console.log('name1 '+this.name1)
}
@Entry
@Component
struct Home {
@State message: string = 'Hello World';
onPageShow() {
const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // 获取传递过来的参数对象
if (params) {
const info: string = params.info as string; // 获取info属性的值
}
}
...
}
栈内存&堆内存 栈(stack) 栈stack为自动分配的内存空间,它由系统自动释放; 堆(heap) 堆heap是动态分配的内存,大小不定也不会自动释放。
JavaScript中的内存也分为栈内存和堆内存。一般来说: 栈内存中存放的是存储对象的地址; 而堆内存中存放的是存储对象的具体内容。 对于原始类型的值而言,其地址和具体内容都存在于栈内存中; 而基于引用类型的值,其地址存在栈内存,其具体内容存在堆内存中。 堆内存与栈内存是有区别的:栈内存运行效率比堆内存高,空间相对推内存来说较小,反之则是堆内存的特点。 所以将构造简单的原始类型值放在栈内存中,将构造复杂的引用类型值放在堆中而不影响栈的效率。
在鸿蒙中Router模块提供了两种跳转模式,分别是router.pushUrl和router.replaceUrl。这两种模式决定了目标页面是否会替换当前页。
同时,Router模块提供了两种实例模式,分别是Standard和Single。这两种模式决定了目标url是否会对应多个实例。 Standard:多实例模式,也是默认情况下的跳转模式。目标页面会被添加到页面栈顶,无论栈中是否存在相同url的页面。
Single:单实例模式。如果目标页面的url已经存在于页面栈中,则会将离栈顶最近的同url页面移动到栈顶,该页面成为新建页。如果目标页面的url在页面栈中不存在同url页面,则按照默认的多实例模式进行跳转
const params: RouTmp = router.getParams() as RouTmp;
@State name :string = (router.getParams() as string)?.['name']
接受路由参数时候,也有几种写法,以下其中一种
@Entry
@Component
struct Home {
@State message: string = 'Hello World';
onPageShow() {
const params = this.getUIContext().getRouter().getParams() as Record<string, string>; // 获取传递过来的参数对象
if (params) {
const info: string = params.info as string; // 获取info属性的值
}
}
...
}
官网文档也有很详细的说明 developer.huawei.com/consumer/cn…