组件内守卫
组件内守卫是直接在组件中注册的守卫,允许你根据组件自身状态来控制导航行为。vitarx-router 提供了两个组件内守卫:onBeforeRouteLeave 和 onBeforeRouteUpdate。
onBeforeRouteLeave()
onBeforeRouteLeave() 在组件即将离开当前路由时触发,常用于防止用户在未保存数据时意外离开页面。
签名
ts
/**
* 注册路由离开守卫
* @param guard - 守卫函数,返回 false 可阻止离开
*/
function onBeforeRouteLeave(
guard: (to: RouteLocation, from: RouteLocation) => boolean | void | Promise<boolean | void>
): void阻止离开
返回 false 可以阻止导航,让用户留在当前页面:
ts
import { onBeforeRouteLeave } from 'vitarx-router'
function EditForm() {
const hasUnsavedChanges = ref(false)
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const confirm = window.confirm('你有未保存的更改,确定要离开吗?')
if (!confirm) {
return false
}
}
})
}自动清理
当组件卸载时,通过 onBeforeRouteLeave 注册的守卫会自动清理,无需手动注销。
执行顺序
当存在嵌套组件时,onBeforeRouteLeave 按照 由内到外 的顺序执行:
- 最内层子组件的
onBeforeRouteLeave - 父组件的
onBeforeRouteLeave - 更外层组件的
onBeforeRouteLeave
INFO
由内到外的执行顺序意味着子组件可以先决定是否允许离开,如果子组件阻止了导航,父组件的守卫将不会执行。
onBeforeRouteUpdate()
onBeforeRouteUpdate() 在当前组件复用但路由参数发生变化时触发,常用于在参数变化时重新获取数据。
签名
ts
/**
* 注册路由更新守卫
* @param guard - 守卫函数
*/
function onBeforeRouteUpdate(guard: (to: RouteLocation, from: RouteLocation) => void): void典型用途
当从 /user/1 导航到 /user/2 时,由于使用的是同一个组件,组件不会重新创建。此时可以在 onBeforeRouteUpdate 中获取新数据:
ts
import { onBeforeRouteUpdate } from 'vitarx-router'
function UserProfile() {
const userData = ref(null)
onBeforeRouteUpdate(async (to, from) => {
const userId = to.params.id
userData.value = await fetchUser(userId)
})
}自动清理
与 onBeforeRouteLeave 一样,onBeforeRouteUpdate 注册的守卫在组件卸载时会自动清理。
执行顺序
与 onBeforeRouteLeave 相反,onBeforeRouteUpdate 按照 由外到内 的顺序执行:
- 最外层组件的
onBeforeRouteUpdate - 子组件的
onBeforeRouteUpdate - 最内层组件的
onBeforeRouteUpdate
INFO
由外到内的执行顺序适用于数据加载场景——父组件可以先加载基础数据,子组件再基于父组件的数据加载详细信息。
完整示例
tsx
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vitarx-router'
function UserEdit() {
const form = ref({ name: '', email: '' })
const hasUnsavedChanges = ref(false)
const loading = ref(false)
// 离开守卫:防止未保存时意外离开
onBeforeRouteLeave((to, from) => {
if (hasUnsavedChanges.value) {
const confirmed = window.confirm('你有未保存的更改,确定要离开吗?')
if (!confirmed) {
return false
}
}
})
// 更新守卫:参数变化时重新加载数据
onBeforeRouteUpdate(async (to, from) => {
const userId = to.params.id
loading.value = true
try {
const data = await fetchUser(userId)
form.value = { name: data.name, email: data.email }
hasUnsavedChanges.value = false
} finally {
loading.value = false
}
})
return (
<div>
{loading.value ? (
<p>加载中...</p>
) : (
<form>
<input
value={form.value.name}
onInput={e => {
form.value.name = e.target.value
hasUnsavedChanges.value = true
}}
/>
<input
value={form.value.email}
onInput={e => {
form.value.email = e.target.value
hasUnsavedChanges.value = true
}}
/>
</form>
)}
</div>
)
}完整导航流程 — 了解导航从触发到完成的完整解析流程。