组件内守卫

组件内守卫是直接在组件中注册的守卫,允许你根据组件自身状态来控制导航行为。vitarx-router 提供了两个组件内守卫:onBeforeRouteLeaveonBeforeRouteUpdate

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 按照 由内到外 的顺序执行:

  1. 最内层子组件的 onBeforeRouteLeave
  2. 父组件的 onBeforeRouteLeave
  3. 更外层组件的 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 按照 由外到内 的顺序执行:

  1. 最外层组件的 onBeforeRouteUpdate
  2. 子组件的 onBeforeRouteUpdate
  3. 最内层组件的 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>
  )
}

完整导航流程 — 了解导航从触发到完成的完整解析流程。