Vue3开发中,为什么推荐用router-link而不是普通a标签?新手该怎么用才不踩坑?
别小看这两个标签,本质区别完全不一样
普通a标签和router-link看起来都是点击跳转页面,但底层逻辑差得远,这也是推荐后者的核心原因,先回忆下原生的做法:当你点,浏览器会直接向服务器发请求,服务器返回新的HTML、CSS、JS文件,整个页面重新渲染一遍,不仅浪费带宽和加载时间,之前页面的数据状态(比如输入框的内容、滚动条位置)也会全丢,那router-link呢?它是Vue Router官方封装的组件,走的是前端路由,跳转时不会触发浏览器的整页刷新,只是通过修改URL的hash或者history状态(取决于你配置的路由模式),让Vue的响应式系统根据新路径重新渲染对应的组件,数据和状态都能保留,体验就像用原生APP一样丝滑。
可能有人会说,我用a标签加个preventDefault阻止默认行为,自己写JS改URL和渲染组件不行吗?当然可以,但Vue Router已经帮你做了太多细节优化,你自己写很难覆盖到所有情况,比如路径参数的处理、导航守卫的触发、滚动行为的控制、嵌套路由的激活样式,这些手写起来都特别麻烦,还容易出bug,不如直接用官方组件省心。
新手第一次用router-link,这些基础用法必须会
基础用法其实和a标签很像,但要注意几个专有属性,首先是最核心的to属性,它相当于a标签的href,但支持两种写法:字符串写法和对象写法,字符串写法简单直接,比如<router-link to="/about">关于我们</router-link>,适合路径固定不带参数的场景;对象写法功能更强大,能传路径参数、查询参数,还能指定跳转的路由名称,路由名称在你以后可能会改路径的项目里特别好用,比如你把路由名称设为about,以后把路径从/about改成/company-info,只需要改路由配置文件里的path就行,router-link里的代码不用动,对象写法的例子是<router-link :to="{ name: 'user', params: { id: 123 }, query: { type: 'vip' } }">用户中心</router-link>,这里用了冒号绑定to属性,因为对象是动态的,params对应的是路由配置里的动态段(比如路由里写了/user/:id),刷新页面不会丢,query对应的是URL里的问号后面的参数(比如/user/123?type=vip),刷新页面也不会丢,但params更适合放在路径里当“唯一标识”,query适合筛选条件这类可选参数。
然后是激活样式相关的属性,这也是普通a标签很难实现的,不用你自己写JS判断路径是否匹配,默认情况下,router-link在路径匹配时会自动加上两个CSS类:router-link-active和router-link-exact-active,前者是模糊匹配,比如当前路径是/user/123/orders,那跳转到/user、/user/123的router-link都会有这个类;后者是精确匹配,只有当前路径完全和to属性一致时才会加,比如只有跳转到/user/123/orders的router-link会有这个类,你可以在CSS里直接写这两个类的样式,
.router-link-active {
color: #409eff;
border-bottom: 2px solid #409eff;
}
如果不想用默认的类名,也可以用active-class和exact-active-class属性自定义,比如<router-link to="/about" active-class="nav-active" exact-active-class="nav-exact-active">关于我们</router-link>。
还有一个常用的属性是replace,默认情况下router-link跳转是push一个新的历史记录到浏览器的历史栈里,点浏览器的后退按钮能回到前一个页面;如果加了replace,比如<router-link to="/login" replace>登录</router-link>,跳转时会替换掉当前的历史记录,比如你在首页点登录跳到登录页,这时候点后退按钮会直接回到上一个非当前页面(比如首页之前的搜索结果页),而不是从登录页再退到首页再退,适合登录、支付成功后跳转这种不想让用户后退回去的场景。
新手容易踩的7个坑,避过就是老司机
第一个坑:to属性没加冒号,对象写法变成了字符串,比如<router-link to="{ name: 'user' }"></router-link>,这时候Vue会把整个对象当字符串处理,跳转到/%7B%20name:%20'user'%20%7D这个无效路径,解决方案是对象写法一定要加冒号绑定。
第二个坑:嵌套路由的路径拼接错了,比如父路由的path是/user,子路由的path写成了/orders,那完整路径就是/orders而不是/user/orders,因为子路由path开头带/就是绝对路径,不带/才是相对路径,会自动拼接父路由的path,如果子路由想用父路由的router-view渲染,父路由的path不能加redirect(除非你想默认显示某个子路由),redirect会直接跳转到指定路径,不会渲染父组件。
第三个坑:路径参数的key没写对,比如路由配置里的动态段是/user/:userId,但router-link的params里传的是{ id: 123 },这时候Vue会找不到对应的参数,跳转后的URL里会是空的,比如/user/,解决方案是params里的key必须和路由配置里的动态段完全一致。
第四个坑:刷新页面后路径参数丢了,这种情况只会出现在用对象写法但同时又把动态参数写在path属性里的情况吗?不对,其实如果用params属性传参但没有配合路由名称(也就是只用了path和params),那刷新页面后params就会丢,解决方案是传路径参数一定要配合路由名称,或者直接把参数拼在字符串路径里,比如<router-link to="/user/123"></router-link>。
第五个坑:激活样式不生效,可能的原因有三个:一是路径没匹配对,比如用了exact匹配但路径多了个查询参数;二是自定义的类名和默认的类名冲突了;三是样式加了scoped但没有穿透,因为router-link渲染出来的默认是a标签,如果你在子组件里写加了scoped的样式,可能穿透不到父组件渲染的router-link(或者子组件的router-link?哦不对,scoped是限制在当前组件的元素上的,router-link是在当前组件里的话应该没问题,但如果router-link是封装在第三方组件里的,就需要用深度选择器,比如Vue3里的deep(.router-link-active))。
第六个坑:router-link渲染出来的不是a标签,比如你想把它渲染成一个button,或者是一个div加图标,这时候可以用tag属性吗?等下,Vue3的Vue Router 4.x里已经把tag属性废弃了!很多从Vue2转过来的新手会踩这个坑,解决方案是用作用域插槽,比如渲染成button的写法是:
<router-link :to="{ name: 'about' }" v-slot="{ navigate }">
<button @click="navigate">关于我们</button>
</router-link>
navigate是一个函数,点击时调用它就会触发前端路由跳转,这个比tag属性灵活多了,你可以随便写里面的内容,不管是button、div、span还是图片、列表项都可以。
第七个坑:点击嵌套很深的router-link没有反应,可能的原因是你在父元素上写了@click.stop阻止了事件冒泡,或者父元素有z-index设置把router-link盖住了,解决方案是检查父元素的事件修饰符和z-index。
进阶用法小技巧,让你的导航更贴心
除了基础用法和避坑,还有几个进阶小技巧能提升用户体验,第一个是滚动行为的控制,比如你希望从首页跳转到详情页后,滚动条自动回到顶部,或者从详情页跳回列表页后,滚动条自动回到之前的位置,这时候可以在路由配置文件里的createRouter函数里加scrollBehavior选项,
const router = createRouter({
history: createWebHistory(),
routes,
scrollBehavior(to, from, savedPosition) {
if (savedPosition) {
// 如果有保存的滚动位置,就回到那里
return savedPosition
} else {
// 否则回到顶部
return { top: 0 }
}
}
})
savedPosition是Vue Router自动保存的,只有当用户点击浏览器的前进或后退按钮时才会有值。
第二个是预加载路由组件,比如你有一个很大的详情页组件,不想用户点击router-link后才加载,导致白屏,可以用linkActiveClass或者linkExactActiveClass配合CSS的hover事件,或者用Vue Router 4.x里的prefetch属性(不过这个属性需要配合Vite或者Webpack的配置使用,才能实现真正的按需预加载)。
第三个是动态禁用router-link,比如当用户未登录时,跳转到用户中心的router-link应该禁用,这时候可以用作用域插槽里的isActive、isExactActive、href、navigate这些属性,
<router-link :to="{ name: 'user' }" v-slot="{ navigate, isActive }">
<button :disabled="!isLoggedIn" @click="isLoggedIn && navigate" :class="{ active: isActive }">
用户中心
</button>
</router-link>
这里加了disabled属性和isLoggedIn的判断,只有登录了才能点击navigate函数。
Vue3里的router-link是Vue Router官方封装的核心组件,比普通a标签好用太多,新手只要掌握了基础用法、避过了常见的坑、再用点进阶小技巧,就能做出体验很好的前端导航了。
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
code前端网
