一、Router Link和普通a标签有啥不一样?
做Vue项目时,页面跳转离不开Router Link,但很多同学刚接触时一头雾水:它和普通a标签区别是啥?动态路由咋传参?激活样式咋调?遇到跳转没反应该咋排查?这篇文章把Router Link从基础用法到实战踩坑全拆清楚,新手能快速上手,老手也能补漏~
先搞懂“表面”和“内核”的区别:普通a标签是浏览器原生组件,点击后会整页刷新(比如从localhost:8080/page1
跳到/page2
,浏览器会重新请求服务器);而Router Link是Vue Router提供的前端路由组件,专门给单页应用(SPA)用的,点击后不会刷新页面,而是通过修改URL、匹配路由规则,渲染对应的组件(靠router-view
实现)。
再看“内部渲染”:Router Link最终也会被渲染成a标签,但多了一堆路由逻辑,比如点击时会阻止a标签默认的跳转行为(不然又整页刷新了),还会自动处理“当前路由是否激活”的样式(activeClass
),举个简单对比:
<!-- 普通a标签,整页刷新 --> <a href="/about">关于我们</a> <!-- Router Link,单页无刷新跳转 --> <router-link to="/about">关于我们</router-link>
Router Link的to
属性支持对象语法(传路由name
、params
、query
),灵活性远超a标签的href
,比如要传动态参数:
<router-link :to="{ name: 'user', params: { id: 123 }}">用户123</router-link>
Router Link基础用法:这些细节别踩坑
刚用Router Link时,最容易栽在to
属性、特殊属性(replace
、tag
)这些细节上,逐个拆解:
to
属性的两种写法
to
属性负责指定“跳转到哪”,有静态字符串和动态对象两种写法:
- 静态字符串:适合固定路径,比如
,直接写死路径。联系我们 - 动态对象:适合传参数、匹配路由
name
(比路径更稳定,路径改了name
能不变),格式是{ name: '路由名', params: { 动态参数 }, query: { 查询参数 } }
,比如路由配置里有{ name: 'article', path: '/article/:id' }
,那传参可以写:
<router-link :to="{ name: 'article', params: { id: articleId }, // 对应动态路由/:id query: { tab: 'comment' } // 对应?tab=comment }">文章详情</router-link>
这里要注意:params
传的是动态路由参数(路径里的/:id
),刷新页面后会丢失;query
传的是查询参数(后面的),刷新不会丢,根据需求选传参方式~
replace
属性:控制历史记录
默认情况下,点击Router Link会往浏览器历史记录里新增一条(比如从/page1
到/page2
,返回能回到page1
),加了replace
后,会替换当前历史记录(返回时跳过当前页),场景:比如支付成功页,希望用户返回时直接回到订单列表,不用经过支付页,就可以加replace
:
<router-link to="/pay/success" replace>支付成功</router-link>
tag
属性:把Router Link渲染成其他标签
默认Router Link渲染成a标签,但有时候需要渲染成
<router-link to="/home" tag="li">首页</router-link> <!-- 渲染后是<li>首页</li>,但依然有路由跳转功能 -->
动态路由场景:Router Link咋传参才对?
做项目时,“用户详情页”“文章详情页”这类动态路由很常见,Router Link传参得注意匹配路由配置,分两步:
先配好动态路由规则
在router/index.js
里,给路由加动态参数(用占位):
const routes = [ { name: 'user', path: '/user/:id', // :id是动态参数 component: User } ]
Router Link传参的两种姿势
传参要和路由规则对应,不然会跳转到404或者参数丢失。
- 用
params
传动态路由参数:必须配合路由的name
(用path
也能传,但name
更可靠),比如用户ID是123,传参:
<router-link :to="{ name: 'user', params: { id: 123 }}">用户123</router-link> <!-- 匹配后的路径是/user/123 -->
如果用path
传params
,虽然能跳转,但params
会被忽略(这是Vue Router的设计,避免路径和参数不匹配),所以优先用name + params
。
- 用
query
传查询参数:适合非路径必须的参数(比如分页、筛选),格式是?key=value
,比如传页码:
<router-link :to="{ name: 'articleList', query: { page: 2 }}">第2页</router-link> <!-- 匹配后的路径是/articleList?page=2 -->
query
传参刷新页面不会丢,因为参数在URL里;而params
传参如果没配到动态路由里,刷新就没了(比如路由没写:id
,却用params
传id
,刷新后id
会消失),所以传参前一定先看路由配置里有没有对应的动态参数~
激活样式咋精准控制?解决“高亮不对”难题
导航栏点击后要高亮当前页,这是Router Link的核心需求,但新手常遇到“点击子路由,父路由也高亮”“样式死活不生效”这些问题,关键在activeClass
和exactActiveClass
。
默认激活样式:router-link-active
和router-link-exact-active
Vue Router默认给激活的Router Link加两个类:
router-link-active
:只要当前路由包含目标路由就会加(比如路由是/user/123
,目标路由是/user
,也会激活)。router-link-exact-active
:只有完全匹配目标路由才会加(路由是/user/123
,目标路由是/user
,不会激活;只有路由是/user
时才会激活)。
举个场景:导航栏有“首页()”和“用户(/user
)”,点击“用户”进入/user/123
,这时候“首页”的Router Link因为是,会被router-link-active
激活(因为/user/123
包含),导致首页也高亮——这明显不对!这时候就要用exact
解决。
用exact
解决“父路由被误激活”
给Router Link加exact
属性,让它只在完全匹配时激活:
<router-link to="/" exact>首页</router-link> <router-link to="/user">用户</router-link>
这样点击/user/123
时,“首页”的Router Link因为加了exact
,只有路由是时才会激活,就不会误高亮了。
自定义激活类名
默认类名不够用?可以全局或局部自定义:
- 全局配置:在创建路由实例时,用
linkActiveClass
和linkExactActiveClass
指定:
const router = createRouter({ history: createWebHistory(), routes, linkActiveClass: 'my-active', // 替代router-link-active linkExactActiveClass: 'my-exact-active' // 替代router-link-exact-active })
- 局部配置:单个Router Link组件里用
active-class
和exact-active-class
:
<router-link to="/" exact active-class="nav-active" exact-active-class="nav-exact-active" >首页</router-link>
这样就能用自己的类名控制高亮样式,配合CSS写hover、active状态更灵活~
Router Link和导航守卫咋配合?权限控制、页面拦截全靠它
导航守卫(比如beforeEach
、beforeRouteEnter
)是控制路由权限、处理加载状态的关键,Router Link的跳转也会触发这些守卫,举几个实用场景:
全局守卫:判断用户是否登录
比如点击“订单列表”(需要登录),Router Link触发跳转,全局守卫beforeEach
拦截:
router.beforeEach((to, from, next) => { if (to.meta.requiresAuth && !isLogin()) { next('/login') // 没登录,跳转到登录页 } else { next() // 放行 } })
路由配置里给需要权限的路由加meta
:
{ path: '/order', component: Order, meta: { requiresAuth: true } }
这样点击
时,就会触发beforeEach
,检查登录状态。
组件内守卫:离开页面时确认
比如编辑页面,用户输入内容没保存,点击Router Link跳转时,用beforeRouteLeave
提示:
export default { data() { return { formEdited: false } }, beforeRouteLeave(to, from, next) { if (this.formEdited) { if (window.confirm('内容没保存,确定离开?')) { next() } else { next(false) // 取消跳转 } } else { next() } } }
这时候点击其他Router Link(比如跳转到首页),就会触发这个守卫,实现“离开前确认”。
嵌套路由里,Router Link咋处理多层跳转?
做后台管理系统时,经常遇到“父菜单→子菜单”的嵌套路由(比如/home → /home/about
),Router Link在嵌套场景下要注意路径匹配和相对路由。
先配好嵌套路由
在router/index.js
里,用children
数组配置子路由:
const routes = [ { path: '/home', component: Home, children: [ { path: 'about', // 注意:这里没加/,是相对父路由/home的路径 component: HomeAbout } ] } ]
嵌套路由下的Router Link
在Home组件里,跳转到子路由about
,Router Link的to
可以用相对路径:
<template> <div> <!-- 父组件Home里的子路由跳转 --> <router-link to="about">关于Home</router-link> <!-- 渲染后的路径是/home/about --> </div> </template>
如果写绝对路径/to/about
,就会匹配到根路由下的about
(如果有的话),容易导致404,所以嵌套路由里,优先用相对路径,或者用路由name
(更保险)。
父路由和子路由的Router Link激活样式也要注意,比如父路由是/home
,子路由是/home/about
,点击子路由时,父路由的Router Link也会被激活(因为包含/home
),这时候给父路由的Router Link加exact
吗?不行,因为父路由的路径是/home
,子路由是/home/about
,父路由的Router Link的to
是/home
,所以当路由是/home/about
时,父路由的Router Link的activeClass
是否激活?因为/home/about
包含/home
,所以父路由的Router Link会被加上router-link-active
类,这时候如果希望父路由只有在精确匹配/home
时才激活,子路由激活时父路由不激活,就要给父路由的Router Link加exact
:
<router-link to="/home" exact>Home</router-link>
这样点击子路由/home/about
时,父路由的Router Link因为加了exact
,只有路由是/home
时才激活,子路由激活时父路由就不会高亮了。
Router Link跳转没反应?五步排坑法
遇到“点击Router Link没反应,页面也不跳转”,别慌,按这几步排查:
检查路由配置
看目标路由的path
、name
、component
是否配置正确,比如路由配置里写的是path: '/contactus'
,但Router Link的to
是'/contact'
,路径不匹配就跳不动。
检查to
属性绑定
动态绑定to
时,有没有加(v-bind
)?
<!-- 错误:to是字符串,不是动态绑定,params传不进去 --> <router-link to="{ name: 'user', params: { id: 123 }}">用户</router-link> <!-- 正确:加:,动态绑定对象 --> <router-link :to="{ name: 'user', params: { id: 123 }}">用户</router-link>
检查路由模式和后端配置
如果用 本文仅代表作者观点,不代表Code前端网立场。history
模式,后端必须配置 版权声明
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。