Vue Router 指南入门到实战,这些问题你搞懂了吗?
前端项目里用 Vue 开发单页应用(SPA),页面跳转、组件切换这些需求咋实现?Vue Router 作为官方路由工具,能帮我们搞定路由管理,但新手刚接触时总会遇到一堆问题:咋配置?动态路由咋用?路由守卫有啥用?今天就用问答形式,把 Vue Router 从入门到实战的关键问题一次讲清楚~
Vue Router 是什么,能解决项目里哪些问题?
Vue Router 是 Vue 官方的路由管理器,专门给单页应用(SPA)做“页面导航”,SPA 最大特点是整个项目只有一个 HTML 文件,页面切换靠组件渲染实现,这时候就得靠路由来控制“哪个路径显示哪个组件”。
它能解决的核心问题不少:
- URL 和组件的映射:比如访问
/home
显示 Home 组件,/about
显示 About 组件; - 页面跳转无刷新:SPA 跳转不用像多页应用那样整页刷新,路由能让组件切换更丝滑;
- 嵌套视图管理:像后台系统的“侧边栏 + 内容区”结构,子路由能嵌套在父路由里;
- 权限控制:比如某些页面必须登录才能进,路由守卫能拦截验证;
- URL 参数处理:动态路由(如
/user/123
)能传递参数,实现“用户 ID 不同,页面数据不同”。
举个🌰:做电商 App 时,商品列表页点“商品卡片”跳转到详情页,路由就能让 /product/1001
对应 ProductDetail 组件,还能把 1001
当参数传给组件,加载对应商品数据。
怎么给 Vue 项目配置 Vue Router?
配置分安装 → 建路由文件 → 写规则 → 挂载到 Vue 实例这几步,以 Vue 2 + Vue Router 3.x 为例(Vue 3 版本后面单独讲):
-
安装依赖:打开终端,项目根目录执行
npm install vue-router@3
(Vue 2 对应 3.x 版本,Vue 3 用 4.x); -
创建路由文件:在
src
下新建router/index.js
,用来写路由规则; -
定义路由规则:在
index.js
里引入 Vue、VueRouter 和组件,然后配置routes
数组。import Vue from 'vue' import VueRouter from 'vue-router' import Home from '../views/Home.vue' import About from '../views/About.vue' Vue.use(VueRouter) // 注册路由插件 const routes = [ { path: '/', // 路径 name: 'Home', // 路由名(可选) component: Home // 对应的组件 }, { path: '/about', name: 'About', component: About } ] const router = new VueRouter({ routes // 传入规则 }) export default router
-
挂载到根 Vue 实例:打开
src/main.js
,引入 router 并挂载:import Vue from 'vue' import App from './App.vue' import router from './router' // 引入路由实例 new Vue({ router, // 挂载到Vue实例 render: h => h(App) }).$mount('#app')
在 App.vue 里加 <router-view></router-view>
,这个标签是“路由出口”——匹配到的组件会渲染到这里。
<template> <div id="app"> <router-view></router-view> <!-- 组件渲染到这 --> </div> </template>
动态路由参数怎么用,开发中哪些场景会用到?
动态路由就是路径里带可变参数,格式是 /路径/:参数名
,/user/:id
里的 :id
就是参数,组件里可以通过 $route.params.id
拿到这个参数。
场景特别多:用户个人页(不同用户 ID 对应不同页面)、商品详情页(不同商品 ID 加载不同数据)、文章详情页(不同文章 ID 渲染不同内容)…
举个实际开发的🌰:
- 先配置动态路由规则:
const routes = [ { path: '/user/:id', // :id 是动态参数 component: User } ]
- 在 User 组件里获取参数:可以用
$route.params.id
,比如在created
钩子发请求:export default { created() { const userId = this.$route.params.id // 拿到动态参数 this.fetchUserInfo(userId) // 调接口拿用户数据 }, methods: { fetchUserInfo(id) { // 发请求逻辑... } } }
- 注意:如果路由参数变化,但组件没销毁(比如从
/user/1
跳到/user/2
),组件的created
不会重新执行,这时候得用watch
监听$route
变化:watch: { '$route'(to, from) { const newId = to.params.id this.fetchUserInfo(newId) } }
嵌套路由在实际开发中咋玩?为啥要用嵌套?
嵌套路由就是“路由里套路由”,对应页面的嵌套结构,比如后台管理系统常见的布局:顶部导航栏 + 左侧侧边栏 + 右侧内容区,右侧内容区”要根据侧边栏点击显示不同子页面(如首页、订单页、设置页),这时候就需要嵌套路由。
实现步骤分两步:父路由配置 children 数组 + 父组件里放 <router-view>。
举个后台系统的🌰:
- 配置嵌套路由规则:父路由是
/dashboard
,子路由是/dashboard/home
、/dashboard/profile
:const routes = [ { path: '/dashboard', component: Dashboard, // 父组件 children: [ // 子路由数组 { path: 'home', // 注意:路径不用加 / ,会自动拼接成 /dashboard/home component: DashboardHome }, { path: 'profile', component: DashboardProfile } ] } ]
- 在父组件 Dashboard.vue 里加
<router-view>
,子组件会渲染到这里:<template> <div class="dashboard"> <div class="sidebar">侧边栏</div> <div class="content"> <router-view></router-view> <!-- 子组件渲染到这 --> </div> </div> </template>
这样,访问 /dashboard/home
时,Dashboard 组件先渲染,它的 <router-view>
再渲染 DashboardHome 组件,实现“父 - 子”结构的嵌套。
编程式导航和声明式导航有啥区别,啥时候用?
Vue Router 里有两种跳转方式:声明式(<router-link>)和编程式(this.$router.push 等方法),核心区别是“在哪写跳转逻辑”。
- 声明式:用
<router-link to="路径">
标签实现跳转,适合模板里的导航(比如菜单、导航栏),优点是不用写 JS 代码,Vue Router 会自动处理点击事件和路由跳转,例子:<router-link to="/about">关于我们</router-link>
- 编程式:用
this.$router.push('路径')
、this.$router.replace('路径')
等方法,适合逻辑里的跳转(比如按钮点击后判断权限再跳转、表单提交成功后跳转),例子:<button @click="goAbout">跳转到关于页</button> <script> export default { methods: { goAbout() { // 可以加逻辑判断,比如是否登录 this.$router.push('/about') } } } </script>
模板里的跳转优先用声明式(简洁),JS 逻辑里的跳转用编程式(灵活)。
路由守卫怎么理解,项目里怎么用?
路由守卫就是路由导航过程中的“钩子函数”,能在“路由跳转前、跳转后、进入组件前”等时机执行代码,用来做权限验证、数据预加载、修改页面标题这些事。
路由守卫分三类:全局守卫(整个路由系统生效)、路由独享守卫(单个路由生效)、组件内守卫(组件内部生效)。
(1)全局守卫:router.beforeEach
在路由实例里配置,每次路由跳转前都会触发,最典型的场景是登录权限验证:比如某些页面必须登录才能进,没登录就跳转到登录页。
// router/index.js router.beforeEach((to, from, next) => { // to: 要跳转到的目标路由 // from: 从哪个路由跳过来 // next: 必须调用的函数,决定是否跳转 const isLogin = localStorage.getItem('token') // 假设用token判断登录 if (to.meta.requiresAuth && !isLogin) { next('/login') // 没登录且需要权限,跳转到登录页 } else { next() // 放行 } })
上面代码里的 to.meta.requiresAuth
是路由的“元信息”(后面问题会讲),用来标记该路由是否需要权限。
(2)路由独享守卫:beforeEnter
直接写在单个路由规则里,只有进入这个路由时才触发,比如某个路由需要验证参数是否合法:
const routes = [ { path: '/order/:id', component: Order, beforeEnter: (to, from, next) => { const orderId = to.params.id if (/^\d+$/.test(orderId)) { // 验证id是否是数字 next() } else { next('/404') // 不合法跳转到404 } } } ]
(3)组件内守卫:beforeRouteEnter、beforeRouteUpdate、beforeRouteLeave
写在组件内部,控制组件和路由的交互。beforeRouteEnter 在进入组件前触发(此时组件实例还没创建,不能用 this
),适合预加载数据;beforeRouteLeave 在离开组件前触发,适合拦截(比如表单没保存不让走)。
export default { // 进入组件前触发,此时this还不存在,用next传参 beforeRouteEnter(to, from, next) { fetchData().then(data => { next(vm => { // vm是组件实例 vm.data = data // 把数据传给组件 }) }) }, // 路由参数变化时触发(比如从 /user/1 到 /user/2) beforeRouteUpdate(to, from, next) { this.userId = to.params.id this.fetchUserInfo(this.userId) next() }, // 离开组件前触发,可拦截 beforeRouteLeave(to, from, next) { if (this.formDirty) { // 假设表单有未保存内容 if (window.confirm('表单没保存,确定离开?')) { next() } else { next(false) // 取消跳转 } } else { next() } } }
Hash 模式和 History 模式选哪个,有啥坑?
Vue Router 有两种路由模式,决定 URL 的表现形式和底层原理:
(1)Hash 模式(默认)
URL 里带 (http://xxx.com/#/home
),它基于URL 哈希值(#后面的部分)变化实现路由,优点是兼容性好(老浏览器也支持),不用后端配置;缺点是 URL 不太美观,有个 。
(2)History 模式
URL 是正常格式(http://xxx.com/home
),基于 HTML5 的 History API(pushState
、replaceState
)实现,优点是 URL 更“友好”,用户体验好;缺点是需要后端配合,否则刷新页面会 404。
选哪个? 如果项目对 URL 美观度要求高(比如官网、营销页),选 History 模式,但要处理后端配置;如果是内部系统、对兼容性要求高,选 Hash 模式更省心。
History 模式的坑:部署到服务器后,直接刷新 http://xxx.com/home
会报 404,因为服务器没找到对应的资源,解决方法是让服务器把所有路由请求都指向 index.html(前端路由接管),Nginx 配置:
location / { try_files $uri $uri/ /index.html; }
这样,不管用户访问哪个路径,服务器都会返回 index.html,由前端路由来匹配组件。
路由懒加载怎么配置,对性能有啥帮助?
路由懒加载是把每个路由对应的组件打包成单独的小文件(chunk),页面初始加载时只加载首页组件,其他路由组件等用户访问时再加载,这能减少首屏加载时间,提升性能。
配置很简单:把路由的 component
改成动态 import 形式(() => import('组件路径')
)。
举个🌰:普通导入 vs 懒加载导入:
// 普通导入(首屏会加载Home和About组件) import Home from '../views/Home.vue' import About from '../views/About.vue' // 懒加载导入(首屏只加载Home,About等访问时再加载) const Home = () => import('../views/Home.vue') const About = () => import('../views/About.vue') const routes = [ { path: '/', component: Home }, { path: '/about', component: About } ]
这样配置后,Webpack 会自动把每个 import()
对应的组件打成单独的 chunk,浏览器在需要时才加载,首屏 bundle 体积变小,加载更快,用户打开页面时等待时间更短。
多路由出口(命名视图)怎么用,适合哪些场景?
默认情况下,一个页面只有一个 <router-view>
(路由出口),但有时候页面需要同时渲染多个组件(比如头部、侧边栏、主体分别由不同组件组成),这时候就得用命名视图——给 <router-view>
加 name
属性,路由配置里用 components
对应多个组件。
场景:复杂布局页,比如后台管理系统的布局组件,需要同时渲染 Header、Sidebar、Main 三个组件。
实现步骤:
- 在模板里给
<router-view>
加name
:<template> <div class="layout"> <router-view name="header"></router-view> <!-- 命名为header --> <div class="content"> <router-view name="sidebar"></router-view> <!-- 命名为sidebar --> <router-view></router-view> <!-- 默认name是default --> </div> </div> </template>
- 路由配置里用
components
对应多个组件:const routes = [ { path: '/', components: { default: Main, // 对应默认name的router-view header: Header, // 对应name="header"的router-view sidebar: Sidebar // 对应name="sidebar"的router-view } } ]
这样,访问 时,三个 <router-view>
会分别渲染 Main、Header、Sidebar 组件,实现多区域同时渲染。
路由元信息(meta)有啥实际作用,怎么用?
路由元信息是给每个路由配置
版权声明
本文仅代表作者观点,不代表Code前端网立场。
本文系作者Code前端网发表,如需转载,请注明页面地址。
发表评论:
◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。