一、引言
在 Vue.js 开发中,动态路由切换时 (例如/user/foo
导航到/user/bar
),如果组件被复用,生命周期钩子(如created
、mounted
)不会再次执行。
原因: Vue Router 默认会复用组件实例以提升性能。
示例
javascript
// 路由配置
const router = new VueRouter({
routes: [
// 动态路径参数 以冒号开头
{
path: '/user/:id',
component: () => import('./User.vue')
}
]
})
// User.vue
export default {
template: `<div>User {{ $route.params.id }}</div>`,
created() {
console.log('created 触发,当前ID:', this.$route.params.id)
}
}
问题:
- 从
/user/foo
导航到/user/bar
时:- 页面显示的用户ID会更新
- 但
created
不会执行
二、问题原因分析
底层机制:
- 当路由参数变化但组件相同时,Vue Router 会复用现有组件实例
- 设计初衷:减少不必要的组件销毁/重建开销,提升性能
三、解决方案
方案1:监听路由参数变化
Vue 2 + Vue Router 3
javascript
<script>
export default {
watch: {
'$route.params.id': function (newId) {
this.fetchData(newId);
}
}
}
</script>
Vue 3 + Vue Router 4
javascript
<script setup>
import { watch } from 'vue';
import { useRoute } from 'vue-router';
const route = useRoute();
watch(() => route.params.id, (newId) => {
fetchData(newId);
});
</script>
优点:
- 细粒度控制数据更新
- 不破坏组件复用机制
方案2:使用beforeRouteUpdate
导航守卫
Vue 2 + Vue Router 3
javascript
<script>
export default {
beforeRouteUpdate(to, from, next) {
this.fetchData(to.params.id);
next(); // 在 Vue Router 3 中必须显式调用,否则路由会阻塞
}
}
</script>
Vue 3 + Vue Router 4
javascript
<script setup>
import { onBeforeRouteUpdate } from 'vue-router';
onBeforeRouteUpdate((to, from) => {
fetchData(to.params.id);
});
</script>
适用场景:
- 需要路由级别的权限控制
方案3:强制销毁重建组件(Key 策略)
为router-view
绑定唯一key
,确保路由变化时重新创建组件:
html
<router-view :key='$route.fullPath' /> <!-- 任何路由变化都重建组件 -->
<router-view :key='$route.params.id' /> <!-- 仅ID变化时重建组件 -->
四、方案对比
方案 | 适用场景 | 优点 | 缺点 |
---|---|---|---|
watch 监听$route 参数 |
需要精细控制参数变化 | - 无组件销毁开销 - 细粒度控制 | 需手动处理逻辑,可能遗漏某些变化 |
使用beforeRouteUpdate 导航守卫 |
需要路由层面的逻辑控制 | 逻辑集中,便于维护 | 仅适用于路由组件 |
key 策略 |
简单场景,不关心性能或状态保留 | 实现简单 | 组件完全重建,性能低且状态丢失 |