在现代前端开发中,单页应用(SPA)已成为主流趋势,Vue.js 作为一款优秀的 JavaScript 框架,在构建 SPA 方面表现出色。Vue Router 作为 Vue.js 官方的路由管理器,与 Vue.js 核心深度集成,极大地简化了单页应用的路由管理工作。在 Vue 3 中,Vue Router 也进行了升级,带来了新特性与改进,本文将全面深入地介绍 Vue 3 中路由的配置和使用。
一、安装和基础设置
(一)安装 Vue Router
首先,确保你的项目已经初始化好 Vue 3 环境。若尚未安装vue-router,可以通过 npm 或 yarn 进行安装,以 npm 为例,安装命令如下:
npm install vue-router@4
这里指定安装@4版本,是因为 Vue 3 搭配的是 Vue Router 4,它在功能和使用方式上与之前版本有所不同。
(二)创建路由实例
安装完成后,通常在项目的src目录下创建一个router文件夹,在其中新建index.js文件用于配置路由实例。代码示例如下:
// src/router/index.js
import { createRouter, createWebHistory } from 'vue-router'
// 导入路由对应的组件
import Home from '../views/Home.vue'
import About from '../views/About.vue'
const routes = [
{
path: '/',
name: 'Home',
component: Home
},
{
path: '/about',
name: 'About',
component: About
}
]
const router = createRouter({
history: createWebHistory(process.env.BASE_URL),
routes
})
export default router
上述代码中,createRouter用于创建路由实例,createWebHistory则用于启用 HTML5 History 模式,该模式下 URL 更加美观,没有#符号,但需要服务器进行相应配置,否则刷新页面可能出现 404 错误。若不想配置服务器,也可使用createWebHashHistory模式,即 Hash 模式,URL 会带有#符号,兼容性更好。routes数组定义了路由的映射关系,每个对象包含path(路径)、name(路由名称,方便通过名称进行导航)和component(路径对应的组件)。
(三)在 Vue 应用中使用路由
在main.js文件中引入并使用上述创建好的路由实例,代码如下:
// src/main.js
import { createApp } from 'vue'
import App from './App.vue'
import router from './router'
createApp(App).use(router).mount('#app')
通过app.use(router)将路由实例挂载到 Vue 应用中,这样整个应用就具备了路由功能。同时,在根组件App.vue中,需要使用<router - view>标签作为路由出口,用来渲染匹配到的组件。例如:
<template>
<div id="app">
<router - view></router - view>
</div>
</template>
二、路由配置详解
(一)路由模式
Vue Router 4 支持两种主要的路由模式:Hash 模式和 History 模式。
- Hash 模式:使用 URL 的 hash(即#号后面的部分)来模拟一个完整的 URL,当#号后面的内容发生变化时,不会向服务器发送请求。这种模式兼容性好,在一些不支持 HTML5 History API 的老旧浏览器中也能正常使用。配置方式如下:
const router = createRouter({ history: createWebHashHistory(), routes: [...] })
History 模式:利用 HTML5 History API 来实现 URL 的变化,通过pushState和replaceState方法改变浏览器地址栏的 URL,同时不会重新加载页面。这种模式下的 URL 更加简洁美观,符合现代 Web 应用的需求,但如前文所述,需要服务器进行配置,确保所有路径都能正确回退到index.html。配置代码如下:
const router = createRouter({ history: createWebHistory(), routes: [...] })
(二)路由匹配
- 动态路由匹配:在实际应用中,经常需要根据不同的参数来展示不同的内容,这时就可以使用动态路由匹配。例如,要创建一个用户详情页面,每个用户有唯一的 ID,通过 ID 来展示对应用户的信息。定义动态路由的方式如下:
// src/router/index.js import { createRouter, createWebHistory } from 'vue-router' // 导入路由对应的组件 import Home from '../views/Home.vue' import About from '../views/About.vue' const routes = [ { path: '/', name: 'Home', component: Home }, { path: '/about', name: 'About', component: About } ] const router = createRouter({ history: createWebHistory(process.env.BASE_URL), routes }) export default router
上述代码中,createRouter用于创建路由实例,createWebHistory则用于启用 HTML5 History 模式,该模式下 URL 更加美观,没有#符号,但需要服务器进行相应配置,否则刷新页面可能出现 404 错误。若不想配置服务器,也可使用createWebHashHistory模式,即 Hash 模式,URL 会带有#符号,兼容性更好。routes数组定义了路由的映射关系,每个对象包含path(路径)、name(路由名称,方便通过名称进行导航)和component(路径对应的组件)。
(三)在 Vue 应用中使用路由
在main.js文件中引入并使用上述创建好的路由实例,代码如下:
// src/main.js import { createApp } from 'vue' import App from './App.vue' import router from './router' createApp(App).use(router).mount('#app')
通过app.use(router)将路由实例挂载到 Vue 应用中,这样整个应用就具备了路由功能。同时,在根组件App.vue中,需要使用<router - view>标签作为路由出口,用来渲染匹配到的组件。例如:
<template> <div id="app"> <router - view></router - view> </div> </template>
二、路由配置详解
(一)路由模式
Vue Router 4 支持两种主要的路由模式:Hash 模式和 History 模式。
- Hash 模式:使用 URL 的 hash(即#号后面的部分)来模拟一个完整的 URL,当#号后面的内容发生变化时,不会向服务器发送请求。这种模式兼容性好,在一些不支持 HTML5 History API 的老旧浏览器中也能正常使用。配置方式如下:
const router = createRouter({ history: createWebHashHistory(), routes: [...] })
History 模式:利用 HTML5 History API 来实现 URL 的变化,通过pushState和replaceState方法改变浏览器地址栏的 URL,同时不会重新加载页面。这种模式下的 URL 更加简洁美观,符合现代 Web 应用的需求,但如前文所述,需要服务器进行配置,确保所有路径都能正确回退到index.html。配置代码如下:
const router = createRouter({ history: createWebHistory(), routes: [...] })
(二)路由匹配
- 动态路由匹配:在实际应用中,经常需要根据不同的参数来展示不同的内容,这时就可以使用动态路由匹配。例如,要创建一个用户详情页面,每个用户有唯一的 ID,通过 ID 来展示对应用户的信息。定义动态路由的方式如下:
const routes = [ { path: '/user/:id', component: User } ]
在User组件中,可以通过$route.params.id来访问这个动态参数id。例如,在User组件的setup函数中获取参数:
import { useRoute } from 'vue - router' export default { setup() { const route = useRoute() const userId = route.params.id // 可以根据userId进行数据请求等操作 return { userId } } }
路由参数的可选性:有时候,某个动态参数可能是可选的。例如,我们有一个商品详情页面,除了商品 ID 外,还可能有一个查询参数variant用于指定商品的变体。可以这样定义路由:
const routes = [ { path: '/product/:id', name: 'product', component: Product, children: [ { path: 'variant', name: 'variant', component: Variant } ] } ]
在Product组件中,可以通过$route.params.id获取商品 ID,通过$route.query.variant获取变体参数。当访问/product/123时,$route.query.variant为空;当访问/product/123?variant=red时,$route.query.variant的值为red。
(三)嵌套路由
在复杂的应用中,页面往往具有多层嵌套结构,Vue Router 允许配置嵌套路由来满足这种需求。例如,有一个用户管理模块,用户详情页面包含个人资料和用户发布的文章两个子页面。配置嵌套路由的代码如下:
const routes = [ { path: '/user/:id', component: User, children: [ { path: 'profile', name: 'profile', component: UserProfile }, { path: 'posts', name: 'posts', component: UserPosts } ] } ]
在上述代码中,User组件作为父组件,其模板中需要包含<router - view>标签,用于渲染子路由对应的组件。例如:
<template> <div> <h1>用户详情</h1> <router - view></router - view> </div> </template>
当访问/user/123/profile时,UserProfile组件会被渲染到User组件的<router - view>中;当访问/user/123/posts时,UserPosts组件会被渲染。需要注意的是,子路由的path不需要以/开头,它会继承父路由的路径。
三、编程式导航
除了使用<router - link>组件进行声明式导航外,Vue Router 还提供了编程式导航的方式,即通过调用路由实例的方法来实现页面跳转。
(一)使用 push 方法
push方法用于向历史记录中添加一个新的路由记录,从而实现页面跳转。它可以接收多种类型的参数:
- 字符串路径:直接传入目标路径字符串,例如:
router.push('/home')
带有路径的对象:通过对象形式传入路径,这种方式更加灵活,例如:
router.push({ path: '/about' })
命名的路由,并加上参数:如果在定义路由时给路由设置了name,可以通过name来导航,并传入参数,代码如下:
router.push({ name: 'user', params: { id: 123 } })
上述代码会跳转到name为user的路由,并将id参数设置为123。
4. 带查询参数:可以在跳转时携带查询参数,例如:
router.push({ path: '/search', query: { keyword: 'vue' } })
此时,跳转到的 URL 为/search?keyword=vue。
(二)使用 replace 方法
replace方法与push方法类似,不同之处在于replace方法不会向历史记录中添加新记录,而是替换当前的历史记录。例如:
router.replace({ path: '/login' })
执行上述代码后,当前页面会跳转到/login,并且历史记录中当前页面的记录会被/login的记录替换,用户无法通过浏览器的后退按钮回到之前的页面。
(三)使用 go 方法
go方法用于在历史记录中向前或向后跳转指定的步数,类似于浏览器的前进和后退按钮。例如
//向前一页跳转 router.go(1) //向后一页跳转 router.go(-1)
四、路由守卫
路由守卫主要用于通过跳转或取消的方式守卫导航,在路由导航的不同阶段执行特定的逻辑,例如权限验证、页面加载前的数据预取等。
(一)全局前置守卫
全局前置守卫会在每次路由导航之前被调用,其语法如下:
router.beforeEach((to, from) => { // to: 即将进入的目标路由对象 // from: 当前导航正要离开的路由对象 // 可以在这里进行权限验证等操作 if (to.meta.requiresAuth &&!isAuthenticated()) { return { name: 'login' } // 未登录则跳转到登录页面 } return true // 允许导航 })
在上述代码中,to.meta.requiresAuth用于判断目标路由是否需要登录权限,isAuthenticated()是一个自定义函数,用于判断用户是否已经登录。如果用户未登录且目标路由需要权限,则返回一个新的路由对象,跳转到登录页面;否则返回true,允许导航继续进行。
(二)路由独享的守卫
每个路由配置对象可以定义自己的beforeEnter守卫,该守卫仅在进入该路由时被调用。例如:
const routes = [ { path: '/admin', name: 'admin', component: Admin, beforeEnter: (to, from) => { if (!isAdmin()) { return { name: 'home' } // 非管理员用户跳转到首页 } return true } } ]
这里的isAdmin()是一个判断用户是否为管理员的自定义函数,如果用户不是管理员,则跳转到首页,否则允许进入/admin路由。
(三)组件内的守卫
在组件内部也可以定义路由守卫,有以下几种:
- beforeRouteEnter:在渲染该组件的对应路由被验证前调用,此时组件实例还未被创建,不能使用this。例如:
export default { setup() { const beforeRouteEnter = (to, from) => { // 可以在进入路由前进行一些操作,如数据预取 const userId = to.params.id fetchUserData(userId) } return { beforeRouteEnter } } }
beforeRouteUpdate:在当前路由改变,但是该组件被复用时调用,例如,在动态路由参数变化时,组件不会重新创建,而是复用已有的组件实例,此时可以在这个守卫中处理参数变化的逻辑。代码如下:
export default { setup() { const beforeRouteUpdate = (to, from) => { const newId = to.params.id const oldId = from.params.id if (newId!== oldId) { // 根据新的参数重新获取数据 fetchData(newId) } } return { beforeRouteUpdate } } }
beforeRouteLeave:在导航离开渲染该组件的对应路由时调用,可以用于防止用户不小心离开页面,例如,当用户在表单中输入了未保存的数据时,提示用户是否保存。示例代码如下:
<template> <form> <input v - model="formData.name"> <input v - model="formData.email"> </form> </template> <script> export default { data() { return { formData: { name: '', email: '' } } }, setup() { const beforeRouteLeave = (to, from) => { if (Object.keys(this.formData).some(key => this.formData[key])) { const confirmLeave = window.confirm('您有未保存的数据,确定离开吗?') return confirmLeave } return true } return { beforeRouteLeave } } } </script>
五、路由元信息
在定义路由时,可以为每个路由配置meta字段,用于存储一些自定义的元信息,例如页面标题、是否需要权限等。这些元信息可以在路由守卫或组件中获取和使用。例如:
const routes = [ { path: '/dashboard', name: 'dashboard', component: Dashboard, meta: { title: '仪表盘', requiresAuth: true } }, { path: '/login', name: 'login', component: Login, meta: { title: '登录' } } ]
在全局前置守卫中,可以根据meta字段来设置页面标题,例如:
router.beforeEach((to, from) => { document.title = to.meta.title || '默认标题' return true })
在权限验证时,也可以通过meta字段判断目标路由是否需要权限:
router.beforeEach((to, from) => { if (to.meta.requiresAuth &&!isAuthenticated()) { return { name: 'login' } } return true })
通过以上对 Vue 3 路由配置和使用的详细讲解,相信你对 Vue Router 有了更深入的理解。合理运用路由的各种特性,可以构建出更加灵活、高效的单页应用。在实际开发中,根据项目需求不断探索和实践,充分发挥 Vue Router 的强大功能。
希望这篇博客能对你有所帮助,感兴趣的话,请在评论区留言讨论吧!!