Vue2路由怎么学?从基础到实战常见问题全解答
想学Vue2路由却一头雾水?路由配置总出错、传参老丢数据、导航守卫不知咋用…这些问题是不是让你抓耳挠腮?别慌!这篇文章把Vue2路由从基础到实战的常见问题拆碎了讲,不管是刚入门的小白,还是想解决实战难题的开发者,看完都能通透不少~
Vue2路由基础:先搞懂“路由是干啥的”
啥是Vue2路由?和单页应用有啥关系?
Vue路由(vue-router
)是Vue官方的路由管理器,专门帮单页应用(SPA)实现“无刷新页面跳转”,单页应用只有一个HTML页面,靠切换不同组件模拟多页效果,路由就是负责管理“哪个路径该显示哪个组件、怎么跳转”的工具,比如做个博客,点击“首页”“文章列表”“关于我”时,页面不用整页刷新,只是切换对应的组件,这就是路由在背后“牵线搭桥”~
路由模式有hash和history,区别在哪?
Vue2路由默认是hash
模式,URL里带(比如http://xxx/#/home
),后面的路径变化不会让浏览器真的请求服务器;history
模式则是用HTML5的History API,URL更干净(像http://xxx/home
),但部署时得配置服务器(否则直接访问子路径会404),要是做内部系统,hash
模式够稳;要是对外的官网,想要好看的URL,就用history
模式,不过得配合后端配置重定向~
路由里的“路由映射”“路由组件”是啥意思?
路由映射就是“URL路径和组件的绑定规则”,比如配置{ path: '/about', component: About }
,意思是用户访问/about
时,渲染About
组件,这里的About
就是路由组件,它会被渲染到<router-view>
这个“占位容器”里,简单说,路由映射是“规则”,路由组件是“内容”,<router-view>
是“展示容器”~
路由配置入门:从安装到写第一个路由
咋在Vue2项目里装vue-router
?
如果用Vue CLI创建项目,选“Manually select features”时把Router
勾上,CLI会自动装依赖并生成路由模板,要是手动装,先通过包管理工具安装:npm install vue-router@3
(因为Vue2对应vue-router 3.x
,Vue3是x
),然后在src
里新建router
文件夹,写配置文件~
基本的路由配置文件长啥样?
一般在src/router/index.js
里写核心配置:
import Vue from 'vue' import Router from 'vue-router' import Home from '@/components/Home' // 引入路由组件 import About from '@/components/About' Vue.use(Router) // 全局注册路由插件 export default new Router({ routes: [ // 路由规则数组 { path: '/', // 匹配根路径 name: 'Home', // 路由名称(可选,方便编程式导航) component: Home // 对应组件 }, { path: '/about', name: 'About', component: About } ] })
接着在main.js
里把路由实例注入Vue根实例:
import Vue from 'vue' import App from './App.vue' import router from './router' // 引入路由配置 new Vue({ router, // 注入路由,让所有组件能访问$router/$route render: h => h(App) }).$mount('#app')
最后在App.vue
里加<router-view></router-view>
当“组件容器”,用<router-link to="/">首页</router-link>
做跳转链接~
路由组件必须放components
文件夹吗?
不是必须!这只是“约定俗成的规范”,方便团队协作和代码管理,你可以按功能分文件夹(比如pages
放路由组件、components
放通用组件),只要在配置路由时,正确引入组件路径就行,灵活调整~
路由传参:三种方式优缺点+避坑
路由传参有哪几种方式?分别咋用?
主要三种方式,各有适用场景:
query
传参:像GET请求带参数,URL里显示?id=1&name=xxx
,跳转时用<router-link :to="{ path: '/detail', query: { id: 1 }}">
,或编程式导航this.$router.push({ path: '/detail', query: { id: 1 }})
;接收参数用this.$route.query.id
。params
传参:参数“藏”在路由路径里(配合name
跳转时,URL不显示参数),需先在路由配置定义动态路由(比如{ path: '/detail/:id', name: 'Detail', component: Detail }
),跳转用<router-link :to="{ name: 'Detail', params: { id: 1 }}">
或this.$router.push({ name: 'Detail', params: { id: 1 }})
,接收用this.$route.params.id
。- 动态路由参数:本质是
params
的一种,路径里写/:id
,参数“必须传”(否则匹配不到路由),适合商品详情页这类“必须有ID”的场景~
query
和params
传参区别是啥?
最直观的是URL表现:query
参数在URL里可见,刷新页面参数还在;params
如果用name
跳转,参数不在URL里,刷新会丢数据(除非把参数写进路由路径),用path
跳转时,params
会被忽略,所以params
传参一定要用name
!
传参后页面刷新数据没了咋整?
如果是params
传参没配置到路由路径里,刷新肯定丢数据,这时候要么把参数放到query
里,要么在路由配置里把参数写进path
(比如/detail/:id/:name
),还可以在组件的activated
钩子(路由组件被缓存时,created
不触发)里重新取参数,或者用Vuex、localStorage
临时存数据~
导航守卫:控制路由跳转的“门卫”
导航守卫是干啥的?为啥需要它?
导航守卫能在“路由跳转前、跳转中、跳转后”插入逻辑,比如判断用户是否登录、加载进度条、设置页面标题,举个例子:用户要进个人中心,得先验证登录状态,没登录就跳登录页——这就得靠导航守卫“拦一下”~
全局守卫、路由独享守卫、组件内守卫有啥区别?
- 全局守卫:作用于所有路由,比如
router.beforeEach((to, from, next) => { ... })
,每次路由跳转前都触发。 - 路由独享守卫:只作用于某个路由,在路由配置里写
beforeEnter: (to, from, next) => { ... }
,比如某个敏感页面,单独做权限校验。 - 组件内守卫:在路由组件里写,比如
beforeRouteEnter
(组件创建前触发)、beforeRouteUpdate
(路由参数变了但组件复用触发)、beforeRouteLeave
(离开组件前触发),适合组件内自己的逻辑(比如离开编辑页提示“是否保存”)~
咋用导航守卫实现登录拦截?
在全局前置守卫router.beforeEach
里判断登录状态:
router.beforeEach((to, from, next) => { const isLogin = localStorage.getItem('token') // 假设用token判断登录 if (to.meta.requiresAuth) { // 路由元信息标记“是否需要登录” if (isLogin) { next() // 登录了,放行 } else { next('/login') // 没登录,跳登录页 } } else { next() // 不需要登录的页面,直接放行 } })
然后在路由配置里,给需要登录的页面加meta
标记:
{ path: '/profile', name: 'Profile', component: Profile, meta: { requiresAuth: true } // 标记该页面需要登录 }
这样用户访问/profile
时,就会被守卫拦截验证~
动态路由与嵌套路由:应对复杂页面结构
动态路由咋配置?适合啥场景?
动态路由就是“路径里带变量”,比如商品详情页/goods/:id
,用户点击不同商品,id
变化但组件复用,配置时在routes
数组里写:
{ path: '/goods/:id', component: GoodsDetail }
组件里用this.$route.params.id
拿参数,适合详情页、订单页这类“根据不同ID展示内容”的场景~
动态路由匹配不到咋处理?
如果用户输入了不存在的id
(比如/goods/999
但系统没这个商品),可以配置通配符路由“兜底”:
{ path: '*', // 匹配所有未定义的路径 component: NotFound // 404组件 }
注意要把通配符路由放在所有路由规则的最后(因为路由匹配是“从上到下”的,通配符匹配所有,放前面会挡住其他路由)~
嵌套路由是啥?啥时候用?
嵌套路由是“路由里套路由”,比如后台管理系统的layout(侧边栏+主内容区)
区要根据不同路由切换组件,配置时用children
数组:
{ path: '/admin', component: AdminLayout, // 父组件,包含<router-view> children: [ { path: 'dashboard', component: Dashboard }, // 子路由,路径是/admin/dashboard { path: 'settings', component: Settings } ] }
父组件AdminLayout
里得有<router-view>
来渲染子组件,适合有“公共布局(比如头部、侧边栏)”的页面结构~
路由懒加载:让项目加载更快的秘密
路由懒加载是啥?有啥好处?
路由懒加载是把“路由对应的组件”打包成单独的JS文件,用户访问时再加载,而不是一开始全加载,好处是首屏加载更快(减少初始bundle体积)、按需加载(用户没访问的页面,暂时不加载代码),比如用户只访问首页,就不用加载“关于页、详情页”的代码~
咋实现路由懒加载?
用ES6的import()
语法,把原来的“静态引入”改成“动态引入”:
// 原来的静态引入(全量打包) import About from '@/components/About' // 改成懒加载(单独打包,访问时加载) const About = () => import('@/components/About') // 路由配置里直接用 { path: '/about', component: About }
这样About
组件会被单独打包,只有访问/about
时才加载~
能和UI库的按需加载结合吗?
比如Element UI的按需加载,配合路由懒加载,能进一步减小体积,在babel.config.js
里配置按需加载插件后,在路由组件里只引入需要的UI组件:
import { Button, Table } from 'element-ui' // 只加载Button和Table,不加载整个UI库
这样每个路由组件只加载“用到的UI组件”,性能更优~
路由错误处理:解决跳转崩溃、404等问题
路由跳转时出错咋捕获?
用this.$router.push
跳转时,若路径错误或有其他异常,会抛出错误,可以用try...catch
包裹:
try { await this.$router.push('/wrong-path') } catch (error) { console.log('路由跳转出错:', error) this.$router.push('/404') // 跳转到404页面 }
或者在全局的router.onError
里捕获“路由加载时的错误”(比如懒加载组件加载失败):
router.onError((error) => { console.log('路由加载错误:', error) // 处理错误(比如跳转到错误页面) })
404页面咋配置?
在路由规则最后加通配符路由:
{ path: '*', name: 'NotFound', component: () => import('@/components/NotFound') // 懒加载404组件 }
注意要放在所有路由规则的最后,否则会“拦截”其他合法路由~
重复点击路由链接报错咋解决?
Vue2路由在“重复点击同一路由”时,会抛出NavigationDuplicated
错误,可以在router/index.js
里全局捕获:
const originalPush = Router.prototype.push Router.prototype.push = function push(location) { return originalPush.call(this, location).catch(err => err) }
这样重复点击时错误会被捕获,不影响页面~
实战避坑:那些教程没讲的“阴间”问题
路由跳转后页面不更新是咋回事?
因为路由参数变了,但组件复用了(比如从/goods/1
跳到/goods/2
),这时候组件的created
、mounted
不会重新执行,解决方法:
- 用
watch
监听$route
变化:watch: { '$route'(to, from) { this.fetchData(to.params.id) // 路由变化后,重新获取数据 } }
- 用组件内守卫
beforeRouteUpdate
:beforeRouteUpdate(to, from, next) { this.id = to.params.id this.fetchData(this.id) next() }
路由守卫里this
指向不对咋办?
比如在全局守卫router.beforeEach
里,this
默认不是Vue实例(因为守卫是挂载在路由实例上,不是组件内),如果要访问Vuex或全局方法,得用router.app
(路由实例的app
属性是Vue根实例):
router.beforeEach((to, from, next) => { const store = router.app.$store // 访问Vuex if (to.meta.requiresAuth && !store.state.user.isLogin) { next('/login') } else { next() } })
移动端路由切换动画咋实现?
用Vue的过渡动画配合路由,在<router-view>
外面包<transition>
,并设置name
:
<transition name="slide-left"> <router-view></router-view> </transition>
然后写CSS动画:
.slide-left-enter-active, .slide-left-leave-active { transition: all 0.3s ease; } .slide-left-enter, .slide-left-leave-to { transform: translateX(100%); opacity: 0; }
这样路由切换时就有“滑动动画”啦~
多路由出口咋处理?
页面需要多个<router-view>
时(比如侧边栏和内容区分别渲染不同组件),用命名视图:
{ path: '/', components: { default: Home, // 对应未命名的<router-view> sidebar: Sidebar // 对应<router-view name="sidebar"> } }
模板里这样写:
<router-view></router-view> <!-- 渲染Home --> <router-view name="sidebar"></router-view> <!-- 渲染Sidebar -->
学Vue2路由,核心是理解“路径→组件→导航”的联动逻辑,再结合实战踩坑、优化性能,才能真正用顺,现在再回头看开头的问题,是不是觉得清晰多了?把这些知识点拆成小任务(比如先配个简单路由,再玩传参,接着搞守卫),逐步推进,你会发现路由其实没那么难~要是练手的话,不妨做个带“登录、详情页、嵌套布局”的小项目,把这些技巧全用上,绝对能吃透!
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。