一、vue-router link是干啥的?先搞懂单页应用跳转逻辑
做Vue单页应用开发时,导航跳转是绕不开的需求,用原生a标签?刷新页面体验差还容易丢状态;用vue-router的
举个直观对比:如果用原生<a href="/about">关于我们</a>,点击后浏览器会请求新的/about页面,整个页面刷新;但用<router-link to="/about">关于我们</router-link>,它会拦截点击事件,通过JS动态切换页面内容(其实是切换组件),浏览器地址栏变了,但页面没刷新,体验丝滑。
简单说,this.$router.push)省心多了。
vue-router link基础用法:把to、tag、active-class玩明白
新手学
to属性:三种传值方式对应不同场景
to是必须的,告诉组件跳转到哪个路由,它有三种写法:
-
字符串形式:直接写路由路径,适合静态路由,比如跳转到“关于我们”页面:
<router-link to="/about">关于我们</router-link>
-
对象形式(带路径):当需要传查询参数(
?xxx=yyy)或者动态路由参数时,用对象更灵活,比如跳转到文章详情,带文章ID:<router-link :to="{ path: '/article', query: { id: 123 }}">文章123</router-link>点击后地址栏会变成
/article?id=123,目标路由组件里用this.$route.query.id就能拿到参数。 -
对象形式(带命名路由):如果路由配置了
name(更推荐,避免路径硬编码),可以用name传值,比如路由配置是:{ name: 'Article', path: '/article/:id', component: Article }那跳转时可以写:
<router-link :to="{ name: 'Article', params: { id: 123 }}">文章123</router-link>这里用
params传动态路由参数,地址栏会变成/article/123,目标组件用this.$route.params.id获取。注意:用name+params时,不能同时写path,否则params会被忽略!
tag属性:让router-link渲染成任意HTML标签
默认情况下,<a>标签,但有时候我们需要它变成按钮、列表项之类的,比如做导航栏,想让每个菜单项是<li>标签,就可以用tag:
<router-link to="/home" tag="li">首页</router-link>
这样渲染后是<li>首页</li>,同时点击时依然能触发路由跳转。
active-class:给当前激活的路由加样式
导航栏需要“当前页面高亮”,这时候active-class就派上用场,比如想让激活的链接加个红色下划线:
先在CSS里定义.active样式:
.active { border-bottom: 2px solid red; }
然后在router-link里配置:
<router-link to="/home" active-class="active">首页</router-link>
当当前路由是/home时,这个router-link会自动添加active类名,样式就生效了。
小技巧:如果多个router-link都要统一active-class,可以在路由实例里全局配置,不用每个组件重复写:
const router = new VueRouter({
routes,
linkActiveClass: 'active' // 全局设置active-class
})
exact:解决“模糊匹配”导致的active样式混乱
比如有个路由是(首页),另一个是/about,当访问/about时,的router-link也会被认为“匹配”(因为/about包含),导致两个link都高亮,这时候加exact属性就能精确匹配:
<router-link to="/" exact>首页</router-link>
这样只有当路由严格等于时,才会激活这个link的active样式。
vue-router link常见问题:这些坑90%的新手都踩过
学会基础用法后,实际开发中还会遇到各种“诡异”问题,跳转后页面没变化”“传参后参数丢了”“active样式死活不生效”… 逐个拆解:
问题:点击router-link没反应,地址栏也没变
排查方向:
- 路由配置错误:检查
routes里有没有对应的path,比如想跳转到/about,路由里是否配置了{ path: '/about', component: About }? - to属性绑错了:如果用对象形式传参,有没有加v-bind(:)?比如写成
to="{ path: '/about' }"会被当成字符串,正确是:to="{ path: '/about' }"。 - 路由模式冲突:如果用了
history模式,服务器是否配置了fallback( fallback到index.html)?否则直接访问/about会404,导致router-link跳转也失效。
问题:动态路由传参后,目标页面拿不到参数
常见场景:用params传动态路由参数,比如跳转到/article/123,但Article组件里this.$route.params.id是undefined。
原因+解决:
- 路由配置没写动态参数:路由里得是
path: '/article/:id',而不是path: '/article'。 - 用了
path+params:前面说过,用name传参时才能带params,用path的话params会被忽略,所以要么用name+params,要么用path+query。 - 组件复用导致参数没更新:如果
Article组件是复用的(比如从/article/123跳到/article/456,组件实例没销毁),需要用watch监听$route变化:watch: { '$route'(to, from) { // 这里拿到新的to.params.id } }
问题:active-class样式不生效
可能原因:
- 路由匹配规则问题:比如父路由和子路由的link,父路由的link会因为“包含子路由路径”而一直激活,这时候给父路由的link加
exact解决(参考前面exact的用法)。 - 样式作用域问题:如果CSS加了
scoped(比如单文件组件的<style scoped>),active-class的样式可能被限制,解决方法:要么把active样式放到全局CSS,要么用/deep/穿透(比如>>> .active或/deep/ .active)。 - 全局配置和局部配置冲突:如果路由实例里全局设置了
linkActiveClass,同时局部router-link又写了active-class,以局部为准,要统一风格的话,建议全局配置。
问题:嵌套路由下,父路由link的active样式异常
比如有嵌套路由:
{
path: '/user',
component: User,
children: [
{ path: 'profile', component: Profile },
{ path: 'order', component: Order }
]
}
当访问/user/profile时,父路由/user的router-link也会被激活(因为/user/profile包含/user),导致父link一直高亮。
解决:给父路由的router-link设置exact?不行,因为/user/profile的path不是/user,这时候得用linkExactActiveClass(精确激活样式),或者在路由配置里调整匹配逻辑,更简单的是,利用vue-router的匹配逻辑:当子路由激活时,父路由的linkActiveClass也会激活,所以如果要父link只在自身激活时高亮,需要结合exact和子路由的匹配。
其实更简单的方法是,给父路由的router-link设置exact,同时确保子路由的path不是以开头(避免变成根路由),或者,使用linkExactActiveClass来区分“精确激活”和“包含激活”。
全局配置:
const router = new VueRouter({
routes,
linkActiveClass: 'active', // 包含匹配时的样式
linkExactActiveClass: 'exact-active' // 精确匹配时的样式
})
然后父路由的link用exact-active样式,子路由的link用active样式,这样就能区分开。
问题:router-link和编程式导航(this.$router.push)怎么配合?
有时候需要在点击router-link前做权限判断(比如判断用户是否登录),这时候可以给router-link加@click事件,在事件里判断:
<router-link to="/profile" @click="checkAuth">个人中心</router-link>
export default {
methods: {
checkAuth(e) {
if (!this.isLogin) {
e.preventDefault(); // 阻止默认跳转行为
this.$router.push('/login'); // 跳转到登录页
}
// 已登录则正常跳转,不需要处理,因为e.preventDefault()只在未登录时执行
}
}
}
这里要注意:router-link的点击事件中,先执行@click,再执行跳转,所以可以通过e.preventDefault()阻止默认跳转,再手动用编程式导航跳转。
vue-router link实战场景:解决真实项目里的导航需求
光懂理论不够,得落地到项目,分享几个常见实战场景,看完就能照搬:
场景:动态生成导航栏(从后端拿路由数据)
很多后台管理系统,导航栏是后端返回的(比如根据用户权限生成),这时候需要循环渲染router-link:
<template>
<div class="sidebar">
<router-link
v-for="item in menuList"
:key="item.id"
:to="item.to"
:tag="item.tag || 'a'"
>
{{ item.title }}
</router-link>
</div>
</template>
<script>
export default {
data() {
return {
menuList: [] // 从接口获取,结构如:[{ id: 1, title: '首页', to: '/home', tag: 'li' }, ...]
}
},
created() {
this.fetchMenu(); // 调用接口拿导航数据
},
methods: {
fetchMenu() {
// 模拟接口请求
axios.get('/api/menu').then(res => {
this.menuList = res.data;
});
}
}
}
</script>
这样不管后端返回多少导航项,都能动态渲染成router-link,实现权限控制的动态导航。
场景:带权限控制的跳转(未登录不能进个人中心)
前面提过用@click拦截,再复杂点可以封装成自定义指令或混入(mixin),但简单场景直接在组件里处理:
<router-link to="/profile" @click="handleProfileClick">个人中心</router-link>
export default {
data() {
return {
isLogin: false // 实际项目里从vuex或cookie取
}
},
methods: {
handleProfileClick(e) {
if (!this.isLogin) {
e.preventDefault();
this.$message.warning('请先登录'); // 假设用了Element UI的提示
this.$router.push('/login');
}
}
}
}
如果多个页面都要做权限控制,可以把这个逻辑抽到mixin里,减少重复代码。
场景:多语言路由匹配(比如/en/about和/zh/about)
做国际化时,路由可能带语言前缀,这时候router-link的to需要动态拼接语言:
<template>
<div class="lang-nav">
<router-link
v-for="lang in langs"
:key="lang"
:to="`/${lang}/about`"
>
{{ lang === 'en' ? 'About' : '关于我们' }}
</router-link>
</div>
</template>
<script>
export default {
data() {
return {
langs: ['en', 'zh']
}
}
}
</script>
或者更灵活的方式,在路由配置里用动态段:{ path: '/:lang/about', component: About },然后router-link的to用对象形式传params:
<router-link :to="{ name: 'About', params: { lang: 'en' }}">About</router-link>
这样不管语言怎么切换,路由匹配和跳转都能灵活处理。
场景:keep-alive下,router-link跳转后组件状态不重置
用<keep-alive>缓存组件后,从/pageA跳到/pageB再跳回来,pageA的状态还在,但有时候需要重置状态,这时候可以结合router-link的@click,在跳转前销毁组件实例:
<router-link to="/pageB" @click="beforeLeave">去PageB</router-link>
export default {
methods: {
beforeLeave() {
// 找到当前组件的实例,销毁它
this.$destroy();
}
}
}
或者在路由配置里给组件加key,强制刷新:
<router-view :key="$route.fullPath"></router-view>
这样每次路由变化,router-view都会重新渲染组件,状态就重置了,这和router-link的配合在于,router-link的跳转触发路由变化,从而触发router-view的key变化。
掌握vue-router link的核心逻辑
绕了这么多,其实
新手容易踩的坑,本质是对“路由匹配规则”“参数传递方式”“组件复用机制”理解不到位,记住这几点:
to属性的三种写法对应不同传参场景,params必须配合name,query配合path更灵活;active-class和exact解决导航高亮的精准度问题;- 遇到跳转、传参、样式问题,先从路由配置、属性绑定、组件生命周期这几个角度排查;
- 实战中结合动态渲染、权限控制、国际化这些场景,才能真正把router-link用顺手。
最后提醒:vue-router的文档是最好的老师,遇到细节问题随时翻文档(比如linkActiveClass和linkExactActiveClass的区别),把基础逻辑吃透,再复杂的导航需求也能拆解成一个个小问题解决~
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网



发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。