vue-route+keep-aliver+组合式API踩坑
组合API中如何使用route或router
在 Vue 中获取当前路由信息,主要通过 Vue Router 提供的 API 实现:
在组件模板中访问路由信息
在 Vue 组件的模板或逻辑中,可以直接通过this.$route访问当前路由信息(仅在组件实例中可用)
<template>
<div>
<!-- 当前路由路径 -->
<p>当前路径:{{ $route.path }}</p>
<!-- 当前路由名称(需在路由配置中定义 name) -->
<p>路由名称:{{ $route.name }}</p>
<!-- URL 查询参数(如 ?id=1&name=test) -->
<p>查询参数:{{ $route.query }}</p>
<!-- 动态路由参数(如 /user/:id 中的 id) -->
<p>动态参数:{{ $route.params }}</p>
<!-- 完整 URL(包含域名) -->
<p>完整 URL:{{ $route.fullPath }}</p>
</div>
</template>脚本中
<script>
export default {
mounted() {
// 获取当前路由路径
console.log("当前路径:", this.$route.path);
// 获取动态参数
console.log("动态参数:", this.$route.params);
// 获取查询参数
console.log("查询参数:", this.$route.query);
}
};
</script>在组合API中获取路由信息
在 Vue 3 的组合式 API(如<script setup>)中,需通过useRoute函数获取路由信息:
<script setup>
import { useRoute } from 'vue-router';
// 获取当前路由对象
const route = useRoute();
// 访问路由信息
console.log("当前路径:", route.path);
console.log("动态参数:", route.params);
console.log("查询参数:", route.query);
</script>特别注意!route是路由信息!里面不含有路由的方法!如果也要使用路由的方法需要如下:
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
export default function () {
// 路由信息对象(命名改为 route 更规范)
const route = useRoute();
// 路由实例(用于导航操作)
const router = useRouter();
router.go(-1); // 返回上一级
router.push({
name: 'xxxx'
});
} 更多的用法:
// 1. 直接传入路径字符串
router.push('/detail');
// 2. 传入路径字符串 + 查询参数(?id=123)
router.push('/detail?id=123');
// 3. 传入路由配置对象(推荐,更灵活)
router.push({
path: '/detail', // 路径
query: { id: '123' }, // 查询参数(?id=123)
});
// 4. 通过路由名称跳转(需在路由配置中定义 name)
// 假设路由配置为 { path: '/detail', name: 'Detail', ... }
router.push({
name: 'Detail',
params: { id: '123' }, // 动态路由参数(如 /detail/:id)
query: { tab: 'info' }, // 可同时携带查询参数
});监听路由变化
vue3组合式API
<script setup>
import { useRoute, watch } from 'vue-router';
const route = useRoute();
watch(
route,
(to, from) => {
console.log("新路径:", to.path);
console.log("旧路径:", from.path);
},
{ immediate: true } // 立即执行一次(初始加载时)
);
</script>在路由守卫中获取
// 全局前置守卫
router.beforeEach((to, from, next) => {
console.log("即将进入:", to.path);
console.log("即将离开:", from.path);
next(); // 必须调用 next() 放行
});常用路由信息属性
$route或route对象的核心属性:
path:当前路由的路径(字符串,如/user)。name:路由名称(需在路由配置中定义,如{ path: '/user', name: 'User', ... })。params:动态路由参数(对象,如/user/:id匹配后为{ id: '123' })。query:URL 查询参数(对象,如?page=1&size=10对应{ page: '1', size: '10' })。fullPath:完整路径(包含查询参数和哈希,如/user/123?tab=info#top)。meta:路由元信息(在路由配置中定义的meta字段,如权限信息等)。
keep-alive踩坑
比如我有路由结构如下:
const router = createRouter({
history: createWebHashHistory(),
routes: [
{
path: '/',
redirect: '/home'
},
{
path: '/home',
name: 'home',
component: xx,
children: []
},
{
path: '/library',
name: 'library',
component: xx,
children: []
},
{
path: '/mine',
name: 'mine',
component: xx,
children: [
{
path: 'my-cd',
name: 'mine-my-cd',
component: xx
},
]
}
]
});然后在视图组件中添加router-view如下:
APP.vue
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component"></component>
</keep-alive>
</router-view>
home.vue
<router-view v-slot="{ Component }">
<transition appear name="slide">
<component :is="Component"></component>
</transition>
</router-view>
library.vue
<router-view v-slot="{ Component }">
<transition appear name="slide">
<component :is="Component"></component>
</transition>
</router-view>
mine.vue
<router-view v-slot="{ Component }">
<transition appear name="slide">
<keep-alive exclude="mine-my-cdkey">
<component :is="Component"></component>
</keep-alive>
</transition>
</router-view>我在进入/mine/my-cd时发一个请求,
当路由在/mine/my-cd时候刷新页面,会发送一个请求,没问题;
当路由在/mine/,然后点击进入/mine/my-cd时候,也会发送一个请求;
当路由在/home,并且依次进入 /home > /library > /mine,再通过点击进入/mine/my-cd,发现一次会同时发送3个请求!当路由在/home,并且依次进入 /home > > /mine,再通过点击进入/mine/my-cd,发现一次会同时发送2个请求!
点击的路由数跟请求数相关?开什么玩笑?
经过各种排查,发现问题原因出在keep-alive上!
经过AI各种问询,原因如下:
这是因为 <keep-alive> 会缓存组件实例,导致路由切换时组件不会被销毁,进而引发了请求重复执行的问题。
具体原因和原理可以结合你的代码分析如下:为什么去掉 <keep-alive> 后请求恢复正常?
<keep-alive> 的作用<keep-alive> 是 Vue 的内置组件,用于缓存不活动的组件实例(而非销毁它们)。
当你从 mine-my-cd 页面切换到其他页面再返回时,若组件被 <keep-alive> 缓存,组件不会重新触发 setup 或 onMounted 等初始化逻辑,但也不会被销毁。
当 <keep-alive> 存在时:首次进入 mine-my-cdkey:组件初始化,setup 执行,触发 1 次请求。
离开再返回:组件从缓存中恢复,不会重新执行 setup,但可能因路由切换时父组件重新渲染导致组件被重复实例化,从而触发多次请求。
去掉 <keep-alive> 后:路由切换时组件会被彻底销毁(执行 onUnmounted),重新进入时会重新初始化(执行 setup),避免了重复实例化导致的多次请求。所以最终去掉了APP.vue中的keep-alive,一切正常了!
APP.vue
<router-view v-slot="{ Component }">
<component :is="Component"></component>
</router-view>最后也做了一些优化:
mine.vue
<router-view v-slot="{ Component }">
<transition appear name="slide">
<keep-alive exclude="mine-my-cdkey">
<component :is="Component"></component>
</keep-alive>
</transition>
</router-view>exclude="mine-my-cdkey" 这里是排除的组件,排除那个组件就要填入哪个组件的名称(name)即可,就不会被缓存了!
export default {
name: "mine-my-cdkey",
....
}所以再遇到点击一次,请求却重复多发送,建议检查下是不是有keep-alive在作祟!
最后一点:
keep-alive可以结合activated钩子刷新数据(若必须缓存,可在组件激活时手动刷新数据)
// 在 mine-my-cdkey.vue 的 setup 中
import { onActivated } from 'vue';
setup() {
const { fetchCd } = UseMyCd();
// 组件从缓存激活时触发,确保数据最新
onActivated(() => {
fetchCd();
});
}
目录