onBeforeRouteLeave 函数 | Vue Router API
概述
onBeforeRouteLeave 是 Vue Router 提供的组合式 API 函数,用于在组件内添加路由离开守卫。当用户尝试离开当前路由时,这个守卫会被触发,允许你执行清理操作、数据保存或阻止导航。
语法
typescript
function onBeforeRouteLeave(guard: NavigationGuard): void参数
guard
类型: NavigationGuard必需: 是 说明: 导航守卫函数
typescript
type NavigationGuard = (
to: RouteLocationNormalized,
from: RouteLocationNormalized,
next: NavigationGuardNext
) => any基本用法
基础离开守卫
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
onBeforeRouteLeave((to, from, next) => {
if (confirm('确定要离开当前页面吗?未保存的更改将会丢失。')) {
next() // 允许离开
} else {
next(false) // 阻止离开
}
})
</script>异步离开确认
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
import { ref } from 'vue'
const hasUnsavedChanges = ref(false)
onBeforeRouteLeave(async (to, from, next) => {
if (hasUnsavedChanges.value) {
const confirmed = await showConfirmationDialog(
'有未保存的更改',
'确定要离开吗?未保存的更改将会丢失。'
)
if (confirmed) {
next()
} else {
next(false)
}
} else {
next() // 没有未保存的更改,直接允许离开
}
})
</script>实际应用场景
场景 1:表单数据保护
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
import { ref, watch } from 'vue'
const formData = ref({
title: '',
content: '',
tags: []
})
const originalData = ref({})
const hasChanges = ref(false)
// 监听表单变化
watch(formData, (newVal) => {
hasChanges.value = JSON.stringify(newVal) !== JSON.stringify(originalData.value)
}, { deep: true })
onBeforeRouteLeave((to, from, next) => {
if (hasChanges.value) {
const answer = confirm('表单有未保存的更改,确定要离开吗?')
if (answer) {
next()
} else {
next(false)
}
} else {
next()
}
})
// 初始化原始数据
function initializeData(data) {
formData.value = { ...data }
originalData.value = { ...data }
hasChanges.value = false
}
</script>场景 2:资源清理
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
import { onUnmounted } from 'vue'
const subscriptions = ref([])
const timers = ref([])
// 订阅数据
function subscribeToData() {
const subscription = api.subscribe('data-update', handleDataUpdate)
subscriptions.value.push(subscription)
}
// 设置定时器
function startPolling() {
const timer = setInterval(fetchData, 5000)
timers.value.push(timer)
}
onBeforeRouteLeave((to, from, next) => {
// 清理订阅
subscriptions.value.forEach(sub => sub.unsubscribe())
subscriptions.value = []
// 清理定时器
timers.value.forEach(timer => clearInterval(timer))
timers.value = []
next() // 允许离开
})
// 组件卸载时也清理(双重保险)
onUnmounted(() => {
subscriptions.value.forEach(sub => sub.unsubscribe())
timers.value.forEach(timer => clearInterval(timer))
})
</script>场景 3:工作流导航控制
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
const currentStep = ref(1)
const completedSteps = ref([])
onBeforeRouteLeave((to, from, next) => {
// 检查是否允许离开当前步骤
if (to.name === 'workflow-step' && to.params.step < currentStep.value) {
// 允许返回之前的步骤
next()
} else if (!completedSteps.value.includes(currentStep.value)) {
// 当前步骤未完成,需要确认
const confirmed = confirm('当前步骤尚未完成,确定要离开吗?')
if (confirmed) {
next()
} else {
next(false)
}
} else {
// 步骤已完成,允许离开
next()
}
})
function markStepCompleted(step) {
if (!completedSteps.value.includes(step)) {
completedSteps.value.push(step)
}
}
</script>高级用法
条件性离开守卫
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
import { computed } from 'vue'
const isEditing = ref(false)
const hasUnsavedChanges = ref(false)
// 只在编辑模式下启用离开守卫
const shouldProtectNavigation = computed(() =>
isEditing.value && hasUnsavedChanges.value
)
onBeforeRouteLeave((to, from, next) => {
if (shouldProtectNavigation.value) {
showSavePrompt().then((result) => {
switch (result) {
case 'save':
saveChanges().then(() => next())
break
case 'discard':
next()
break
case 'cancel':
next(false)
break
}
})
} else {
next()
}
})
</script>与状态管理集成
vue
<script setup>
import { onBeforeRouteLeave } from 'vue-router'
import { useFormStore } from '@/stores/form'
const formStore = useFormStore()
onBeforeRouteLeave((to, from, next) => {
if (formStore.hasUnsavedChanges) {
formStore.showLeaveConfirmation = true
formStore.pendingNavigation = { to, from, next }
} else {
next()
}
})
// 在状态管理中处理确认结果
function handleLeaveConfirmation(confirmed) {
if (confirmed) {
formStore.pendingNavigation.next()
} else {
formStore.pendingNavigation.next(false)
}
formStore.showLeaveConfirmation = false
formStore.pendingNavigation = null
}
</script>最佳实践
1. 用户友好的确认提示
javascript
async function showUserFriendlyConfirm(message) {
// 使用自定义确认对话框而不是原生 confirm
return new Promise((resolve) => {
showModal({
title: '确认离开',
message,
buttons: [
{ text: '保存并离开', action: 'save' },
{ text: '直接离开', action: 'leave' },
{ text: '取消', action: 'cancel' }
],
onClose: (action) => {
resolve(action)
}
})
})
}2. 自动保存策略
javascript
onBeforeRouteLeave(async (to, from, next) => {
if (hasUnsavedChanges.value) {
try {
// 尝试自动保存
await autoSave()
next()
} catch (error) {
// 自动保存失败,让用户决定
const action = await showSavePrompt()
if (action === 'leave') {
next()
} else {
next(false)
}
}
} else {
next()
}
})3. 性能优化
javascript
// 避免在每次导航时都创建新函数
const leaveGuard = (to, from, next) => {
if (shouldBlockNavigation.value) {
handleBlockedNavigation(to, from, next)
} else {
next()
}
}
onBeforeRouteLeave(leaveGuard)注意事项
- 组件生命周期 - 守卫只在组件激活时有效
- 异步操作 - 确保正确处理异步确认逻辑
- 内存泄漏 - 及时清理事件监听器和定时器
- 用户体验 - 避免过度使用离开确认,只在必要时提示
兼容性
- Vue 3.0+
- 组合式 API
- TypeScript 支持
🛡️ 提示:
onBeforeRouteLeave是保护用户数据的重要工具,合理使用可以防止意外数据丢失,提升应用的专业性。