Vue Router的该怎么用?常见问题全解答
刚接触Vue Router的同学,肯定对
基础用法:怎么实现页面跳转?
Vue Router里的
最基础的用法是通过to属性指定目标路径:
- 字符串路径:直接写要跳转的路由地址,比如跳转到首页:
<router-link to="/home">首页</router-link>
- 对象形式:当需要传参、指定路由名称时更灵活,比如路由配置里给某个页面起了
name
(如name: 'User'
),可以这样写:<router-link :to="{ name: 'User', params: { id: 123 }, query: { tab: 'info' } }">用户页</router-link>
这里
name
对应路由的名称,params
传动态参数,query
传查询参数。
以前版本里还能通过tag
属性指定tag
属性被移除了,现在更推荐用v-slot来自定义渲染结构(后面进阶部分会讲),不过新手阶段先掌握to
属性的基本用法,就能完成大部分跳转需求~
和普通标签有啥区别?
很多同学会疑惑:既然都是“链接”,为啥不用标签?这得从单页应用(SPA)的原理说起——
普通标签跳转时,浏览器会重新请求服务器,刷新整个页面,但Vue做的是单页应用,所有页面切换都该在“前端内部”完成(只更新页面里的组件,不刷新整个页面),这时候
- 无刷新跳转:
基于Vue Router的路由模式(history或hash)实现“前端路由”,点击时只会更新页面里的组件,不会触发全页面刷新,体验更流畅。 - 自动管理激活状态:当当前路由和
的 to
路径匹配时,它会自动添加激活类(比如默认的router-link-active
),方便做导航高亮,而标签得自己写JS判断路径来加类,麻烦多了。 - 传参更灵活:
的 to
属性支持对象形式,能轻松传params
(动态路由参数)、query
(查询参数);标签只能手动拼接URL(比如<a href="/user?id=123">
),不仅麻烦,还容易出错。
简单说:是“传统多页应用”的跳转方式,
用传参有哪些方式?
页面跳转时经常需要传数据(比如用户ID、筛选条件),
params传参(动态路由参数)
适合路径中需要包含参数的场景(比如用户详情页/user/123
,123是用户ID),步骤分两步:
- 配置动态路由:在路由规则里用
“:参数名”
定义,const routes = [ { path: '/user/:id', name: 'User', component: User } ]
- 在
里传参 :用对象形式的to
,通过params
传值:<router-link :to="{ name: 'User', params: { id: 123 } }">用户123</router-link>
这里必须用
name
匹配路由(用path
的话params
会被忽略,这点要注意!)。
特点:参数会嵌入URL路径(比如/user/123
),刷新页面时参数不会丢失(因为路由配置里有/:id
,属于路由的一部分),但如果路由没配置动态参数,直接用params
传参,刷新后参数会消失哦~
query传参(查询参数)
适合可选参数、筛选条件这类场景(比如列表页的搜索关键词、分页页码),用法更简单:
直接在to
的对象里加query
属性,
<router-link :to="{ path: '/about', query: { msg: 'hello', page: 2 } }">关于页</router-link>
跳转后URL会变成/about?msg=hello&page=2
。
特点:参数在URL的后面,刷新页面时参数会保留(因为属于URL的一部分),但如果是敏感数据不适合用query
(会暴露在URL里),用query
传参时,to
里用path
或name
都可以~
接收参数也很简单:在目标组件里通过this.$route.params.id
(取params
参数)或this.$route.query.msg
(取query
参数)就能拿到值~
如何给设置激活样式?
导航栏需要“当前页面高亮”是常见需求,
active-class:匹配时的激活类
当to
路径和当前路由“部分匹配”时,会自动添加active-class
指定的类,默认类名是router-link-active
,也可以自己定义:
比如想把激活类改成my-active
:
<router-link to="/home" active-class="my-active">首页</router-link>
然后在CSS里写.my-active
的样式(比如改变文字颜色、加下划线)。
还能全局配置激活类:在创建路由实例时(createRouter
),通过linkActiveClass
选项统一设置,
const router = createRouter({ history: createWebHistory(), routes, linkActiveClass: 'global-active-class' })
这样所有active-class
都会变成global-active-class
,不用每个组件重复写。
exact-active-class:精确匹配的激活类
有时候会遇到“路由嵌套”导致的激活问题,比如根路由是,子路由是/about
,当跳转到/about
时,的/about
包含),这时候就需要精确匹配:
给exact
属性,同时用exact-active-class
指定精确匹配时的类:
<router-link to="/" exact exact-active-class="exact-active">首页</router-link>
这样只有当路径完全等于时,才会添加exact-active
类,子路由跳转时就不会误激活啦~
嵌套路由里咋用?
很多项目有“父页面包含子页面”的结构(比如后台管理系统,左侧导航是父路由,右侧内容是子路由),这时候
先看路由配置的结构:
const routes = [ { path: '/dashboard', component: Dashboard, children: [ { path: 'analysis', component: Analysis }, // 子路由,路径是/dashboard/analysis { path: 'statistics', component: Statistics } ] } ]
在父组件Dashboard
的模板里,要跳转到子路由,
<template> <div class="dashboard"> <router-link to="analysis">分析页</router-link> <router-link to="statistics">统计页</router-link> <router-view></router-view> <!-- 子路由组件渲染的地方 --> </div> </template>
这里的to="analysis"
是相对路径,会自动拼接父路由的path
(/dashboard
),变成/dashboard/analysis
,如果用绝对路径,得写to="/dashboard/analysis"
,但相对路径更灵活,父路由path
变化时不用改子路由的link~
如果子路由的path
是空字符串(比如children
里{ path: '', component: Overview }
),那跳转到父路由时会默认显示Overview
组件,这时候<router-link to="" />
就能跳转过去~
动态路由场景下怎么处理?
比如做“用户列表→用户详情”的功能,每个用户对应/user/:id
,这时候需要循环渲染id
。
假设用户数据是users
数组,每个用户有id
和name
,写法可以是:
<template> <div class="user-list"> <router-link v-for="user in users" :key="user.id" :to="{ name: 'User', params: { id: user.id } }" >{{ user.name }}</router-link> </div> </template>
这里要注意路由组件复用的问题:当从/user/1
跳转到/user/2
时,User
组件的实例会被复用(因为路由路径变化但组件相同),这时候组件的created
钩子不会重新执行,导致数据没更新,解决办法有两种:
- 监听
$route
变化:在User
组件里用watch
监听$route
:watch: { '$route' (to, from) { // 这里获取to.params.id,重新请求数据 } }
- 使用
beforeRouteUpdate
钩子:组件内定义beforeRouteUpdate(to, from, next) { // 处理参数变化,更新数据 next() }
所以动态路由场景下,
和编程式导航怎么配合?
Vue Router里除了this.$router.push()
),两者各有适用场景,也能配合使用:
声明式 vs 编程式
配合使用的场景
比如有个“提交表单”按钮,点击后要先验证表单,再跳转,这时候可以用<button>
,点击事件里写逻辑,再调用编程式导航:
<template> <button @click="handleSubmit">提交</button> </template> <script> export default { methods: { handleSubmit() { if (this.formValid()) { // 验证表单 this.$router.push('/success') // 编程式导航跳转 } } } } </script>
但如果想保留@click.native.prevent
,在事件里处理逻辑后再跳转:
<router-link to="/success" @click.native.prevent="handleSubmit">提交</router-link>
这里.native
是监听原生点击事件,.prevent
是阻止默认跳转(因为要自己控制什么时候跳),在handleSubmit
里处理完逻辑后,再调用this.$router.push('/success')
~
性能优化要注意啥?
如果项目里有大量
避免不必要的重渲染
结合路由懒加载
路由懒加载是指“访问该路由时才加载对应的组件代码”,配置方式是在路由规则里用() => import('./views/Home.vue')
。
减少复杂计算在里
如果to
属性绑定的是一个复杂的计算属性或方法,每次组件渲染都会重新计算,拖慢速度,可以把计算逻辑提前到data
或computed
里,再绑定给to
:
<script> export default { computed: { userPath() { return { name: 'User', params: { id: this.userId } } } } } </script> <template> <router-link :to="userPath">用户页</router-link> </template>
这样计算属性只会在依赖变化时重新计算,避免不必要的性能消耗~
到这里,
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。