页面路由
页面路由
导入模块
import router from '@system.router'
接口定义
push
跳转到应用内的指定页面。options
参数属性说明:
uri
:目标页面的名字,必须在mainfest.json
中配置;params
:跳转时需要传递的数据,params
参数的属性会替换目标页面的data
属性值。
push()
返回一个 Promise 对象,它会在目标页面退出之后兑现并返回自定义的结果。例如:
const result = await router.push({ uri: 'PageName' })
console.log("the page 'PageName' was closed with the result:", result)
其中 result
是由 close()
方法指定的页面返回值,你可以通过上面的方法来获取。
注意
页面的返回时间通常取决于用户操作,所以 await router.push()
可能会等待很长时间。如果不需要获取页面的返回值则不建议通过 await
等待页面返回。
replace
跳转到应用内的指定页面并关闭当前页面。options
参数属性说明:
uri
:目标页面的名字,必须在mainfest.json
中配置;params
:跳转时需要传递的数据,params
参数的属性会替换目标页面的data
属性值。
如果当前页面是通过 push()
方法弹出的,由于 replace()
方法会替换当前页面,这会导致 push()
返回的 Promise 对象兑现。
back
返回到名为 name
的页面,如果 name
为空或者不传递这个参数,router.back()
就返回到上一级页面。
调用 back()
方法会导致弹出相关页面的 push()
方法所返回的 Promise 兑现。
close
关闭指定页面。page
是一个页面的 view-model 对象。例如:
router.close(this.$page)
router.close()
方法可以关闭应用内的任意页面。如果目标页面位于页面栈顶端,那么 router.close()
和 router.back()
等效。router.close()
还可以正确关闭悬浮页面。
可选参数 result
用于指定页面的返回值,即弹出该页面的 router.push()
或 prompt.showPopup()
返回的 Promise 兑现时的结果。考虑到有很多种方法退出页面(如用户侧滑、router.back()
方法等),你可以在页面组件的 onDestroy()
生命周期函数中显式调用 close()
方法以确保传递页面返回值:
import router from '@system.router'
export default {
// 这是一个组件对象 ...
onDestroy() {
router.close(this.$page, this.pageResult)
},
// 假设某个方法会设置页面返回值
someMethod() {
this.pageResult = { message: 'some page result' }
},
}
提示
在页面 onDestroy()
返回前多次对页面调用 router.close()
方法并传递了 result
参数时,仅最后一次调用会生效为页面的返回值。这也是建议在 onDestroy()
生命周期函数中通过 close()
方法来返回值的原因。
clear
清空所有底层页面,仅保留顶层页面。调用 clear()
方法不会播放页面转场动画。在退出所有底层页面之后兑现本方法返回的 Promise 对象。
getPages
获取当前应用页面栈中所有页面的页面组件。
getLength
获取当前应用页面栈中页面数量。
getPagesName
获取当前应用页面栈中所有页面的名称。
getPage
获取当前应用中由 index
指定的页面组件。index
是页面的索引(即在页面栈中的位置)。如果查找的页面不存在则返回 undefined
。
getIndex
获取当前应用中由页面组件 component
指定的页面索引。如果查找的页面不存在则返回 undefined
。
queryPage
获取页面栈中名为 name
的所有页面列表,页面列表和页面栈的顺序相同。
queryIndex
获取页面栈中名为 name
的所有页面索引,页面索引值的顺序和页面栈的顺序相同。
开发笔记
重复弹出页面
错误地使用 router.push()
方法可能导致重复弹出同一个页面。考虑这样一个元素:
<p on:click="onClick">Click Me!</p>
当组件的 onClick()
事件回调方法只是简单地弹出新页面时不会有任何问题:
export default{
onClick() {
router.push({ uri: 'CoverPage' })
}
}
因为页面在播放转场动画(如果有的话)时不会响应手势,因此不会重复调用 router.push()
。但是,如果 onClick()
在异步操作之后再调用 router.push()
就可能出问题,例如:
export default{
async onClick() {
// 这里使用一秒钟的定时器模拟异步操作。真实的异步操作,
// 如文件读写、网络状态查询也会出现相同的问题
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
// 在异步操作之后再调用 router.push()
router.push({ uri: 'CoverPage' })
}
}
如果用户在异步操作(示例中为定时器)期间多次点击 “Click Me!” 按钮就会重复弹出页面。你可以尝试下面的 demo 来验证它:
首先,请在一秒钟内迅速多次点击 “Click Me!” 按钮,这会导致重复弹出 Cover Page,你可以通过该页面显示的计数来观察重复弹出的次数。
接下来,点击 Cover Page 或者右滑即可返回到上一级页面。此时你会发现:无论怎样快速、连续地点击,页面总是逐个返回,而不会重复操作,因为转场动画期间不会响应手势。
避免异步操作
如果要在手势操作(如 click 手势)的回调函数中跳转页面,应当避免异步操作,因为这不仅容易导致重复弹出页面,还会增加手势响应的延迟。尤其是要注意某些异步操作的延迟是不可控的,例如弱网环境下检查在线状态可能要很长时间。
因此,在需要通过点击触发页面跳转的场景中,最好将可能的网络访问转移到新页面中,并通过加载动画来呈现忙状态。
规避方法
如果必须在手势触发的页面跳转之前进行异步操作,请务必通过特定的标志位来避免重复跳转页面。以前面的 onClick()
回调为例:
export default {
async onClick() {
// 添加 isClicked 标志来跳过重复操作,不需要是响应式属性
if (this.isClicked)
return
// 开始执行手势响应逻辑之前标记 isClicked
this.isClicked = true
await new Promise((resolve, reject) => {
setTimeout(resolve, 1000)
})
router.push({ uri: 'CoverPage' })
// 结束执行手势响应逻辑之后清除 isClicked
this.isClicked = false
}
}
使用相同的方式连续点击 “Click Me!” 按钮将不会重复弹出 Cover Page:
这个示例也证实了异步操作确实会增加页面跳转的延迟,在等待定时器超时的一秒钟内用户看不到任何返回!
替换默认页面
开发者可能不希望应用在启动时进入 manifest.json
的 router.entry
页面。典型的场景是在通过 deeplink 启动应用时,根据具体的请求参数跳转到特定页面,而不是进入 entry 页面。
为此,你只需要在应用启动阶段的 onShow()
生命周期函数调用之前通过 router.push()
弹出你想要的页面即可。通常可以在应用的 onCreate()
或 onRoute()
生命周期函数中跳转指定的首页页面。
一但开发者在应用启动早期手动跳转了页面,就会忽略 manifest.json
的 router.entry
配置项。
开屏界面跳转
许多应用在首次进入时会显示一个开屏 logo 页面,然后再跳转到实际的功能首页。此类场景中一般在 logo 页面中通过 router.replace()
方法来跳转,例如:
// 假设这是 logo 页面的 index.ux 脚本
export default {
onInit() {
// 在开屏 logo 页面延时一段时间之后跳转
setTimeout(() => {
router.replace({ uri: 'MainPage' })
}, 1000)
},
}
这样,在跳转到功能首页之后会自动销毁 logo 页面,而前者将会成为应用的底层页面。