书接上回,我们介绍了如何创建Vue项目、什么是Vue Router,以及实现简单的路由跳转。
在本篇文章中将继续结合官方文档,面向小白,介绍从Vue路由模式、嵌套路由、路由参数传递、导航守卫等等。如果你是一位刚刚接触前端开发的小白,不用担心!在本篇文章中我们将以简单易懂的方式,一步步地引导你了解 Vue Router,并教你在项目中使用。
路由懒加载
在配置路由的时候我们有两种导入路由的方式------静态导入与动态导入,动态导入又称为懒加载。
举个栗子🌰:
js
import { createRouter,createWebHistory } from "vue-router";
import Home from "../views/Home.vue";
const routes = [
{
path: '/home',
name: 'home',
component: Home, //静态导入
},
{
path: '/about',
name: 'about',
component: () => import('../views/About.vue'),// 懒加载(动态导入)
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
这个例子中,Home
组件是静态导入 的。这意味着组件将在应用程序启动时立即加载,无论用户是否访问相关路由。而使用 import()
加载About
组件时,它允许组件异步加载,这意味着只有在需要时(即用户导航到特定路由时)才会从服务器获取组件。这可以显著减少应用程序的初始加载时间,因为组件是按需获取的,这就是所谓的懒加载。相比于一次性加载所有组件,懒加载可以避免初始页面较慢的问题,这也是一种性能优化。
路由模式
Vue Router 4官网将路由模式称为不同的历史模式 ,使用 Vue Router v4.x 创建路由器实例时,history
配置允许我们在不同的历史模式中进行选择。Hash
模式、Memory
模式和history
模式,分别对应createWebHashHistory
、createMemoryHistory
和createWebHistory
函数。
js
import { createRouter,createWebHistory,createMemoryHistory,createWebHashHistory } from "vue-router";
const routes = [
{
path: '/home',
name: 'home',
component: () => import('../views/Home.vue')
},
{
path: '/about',
name: 'about',
component: () => import('../views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(), //使用HTML5模式
//history: createMemoryHistory(), //使用Memory模式
//history: createWebHashHistory(), //使用Hash模式
routes
})
export default router
Hash模式
在hash
模式下,URL中的路由信息会以#
符号开始。
hash
模式的优点是在不需要服务器配置的情况下,可以在前端实现路由,因为#
后的内容不会被发送到服务器,只在浏览器端进行解析。
HTML5模式(History模式)
在history
模式下,URL中的路由信息是正常的路径。
这种模式需要服务器的支持,因为直接访问http://localhost:5173/home
时,服务器需要正确配置以返回正确的页面,而不是产生404错误。
Memory模式
Vue Router 4 中提供了一种额外的路由模式,即 memory
模式。它不会将路由信息保存在浏览器的 URL 中,而是在内存中管理路由状态。
这种模式通常用于在无需更改浏览器 URL 的情况下进行路由导航,例如在一些特殊的组件切换场景中,用的较少。
如何选择模式
- 如果你的应用是一个单页应用并且不需要在服务器端配置额外的规则,那么使用默认的
hash
模式是最简单的选择。 - 如果你有服务器,并且想要URL更好看,可以选择使用
history
模式,但需要确保服务器配置正确。
嵌套路由
嵌套路由允许我们在一个组件内部定义子路由,让我们可以在同一个页面内切换不同的视图。
js
import { createRouter,createWebHistory } from "vue-router";
const routes = [
{
path: '/home',
component: () => import('../views/Home.vue'),
children:[
{
path:'child', // 子路由的路径会拼接到父路由路径后面
component: () => import('../views/Child.vue'),
}
]
},
{
path: '/about',
component: () => import('../views/About.vue')
}
]
const router = createRouter({
history: createWebHistory(),
routes
})
export default router
children
为一个数组,其中每一个对象就是一个子路由,子路由中还可以再配置子路由,需要注意的是子路由的path
不用再接/
,它会自动用/
拼接在父亲的path
后面。
接着我们要做的就是编写Chil.vue
页面以及在父页面中配置router-link
和router-view
。
html
<!-- Child.vue -->
<template>
<div>
这是Child页面
</div>
</template>
html
<!-- Home.vue -->
<template>
<div>
这是Home页面
<router-link to="/home/child">child</router-link>
</div>
<router-view></router-view>
</template>
在父页面中使用router-link
时,to
所对应的地址应该为父路由的path
与子路由的path
拼接后的结果。
效果如下:
路由传参
在 Vue Router 4 中,有几种常见的方式可以进行路由传参,包括 Query、Params、动态路由传参等。
Query路由传参
我们用以下例子来介绍各种传参方式的异同:
在Home页面中我们展示一个用户名和一个展示详情的按钮,点击详情按钮就会跳转到About页面,接收Home的传过来的详情数据,渲染在About页面。
html
<!-- Home.vue -->
<template>
<div>
<h2>这是Home页面</h2>
{{data.name}}
<button @click="check">详情</button>
</div>
</template>
<script setup>
import {useRouter} from 'vue-router'
const router = useRouter()
const data = {
id:'001',
name: '阳阳',
age:'20',
}
const check = ()=>{
router.push({
path: '/about',
query: data
})
}
</script>
编程式导航使用 router push
的时候,改为对象形式新增query
并传入一个对象data
html
<!-- About.vue -->
<template>
<div>
<h2>这是About页面</h2>
<p>学号:{{ route.query.id }}</p>
<p>姓名:{{ route.query.name }}</p>
<p>年龄:{{ route.query.age }}</p>
</div>
</template>
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute()
</script>
在About页面使用 useRoute.query 接收参数。
query 传递的参数会显示在URL地址栏中
Params动态路由传参
在 Vue Router 中,我们可以在路径中使用一个动态字段来实现,我们称之为路径参数
js
{
path: '/about/:id/:name/:age',
name: 'about',
component: () => import('../views/About.vue')
}
这里我们设置的路径中,包含了三个动态路径参数 :id
、:name
、和 :age
。name: 'about'
则便于我们使用params传参。
html
<!-- Home.vue -->
const check = ()=>{
router.push({
name: 'about',
params: data
})
}
使用params
找到对应name
的路由,并传递参数对象data
。
html
<!-- About.vue -->
<template>
<div>
<h2>这是About页面</h2>
<p>学号:{{ route.params.id }}</p>
<p>姓名:{{ route.params.name }}</p>
<p>年龄:{{ route.params.age }}</p>
</div>
</template>
<script setup>
import {useRoute} from 'vue-router'
const route = useRoute()
</script>
在About页面接收参数,并使用route.params
将数据渲染到页面上。
这里,同学们可能会将useRoute
与useRouter
搞混:
useRoute
是一个用于访问当前活动路由状态的 Composition API 函数。它返回当前活动路由的状态对象,包含了路径、参数、查询参数等信息。
useRouter
是一个用于访问 Vue Router 实例的 Composition API 函数。它返回当前 Vue Router 的实例,你可以通过这个实例执行导航、获取路由表等操作。
路由守卫
路由守卫是Vue Router提供的一种机制,允许你在路由导航发生时执行一些操作或控制导航的行为。举个通俗的例子:全局前置守卫就像红绿灯,每次经过路口都要看一下是不是绿灯,确定你是否可以继续前进。
路由守卫有三种:
1:全局钩子: beforeEach
、 afterEach
2:独享守卫(单个路由里面的钩子): beforeEnter
、 beforeLeave
3:组件内守卫:beforeRouteEnter
、 beforeRouteUpdate
、 beforeRouteLeave
全局前置守卫 (beforeEach
)
beforeEach
守卫会在路由切换开始时调用。- 可以用于进行路由鉴权、导航日志记录等操作。
js
router.beforeEach((to, from, next) => {
// to: 即将要进入的目标路由对象
// from: 当前导航正要离开的路由
// next: 是否进行下一步,用于 resolve 这个钩子
// 检查用户是否已登录
if (!isAuthenticated) {//未登录
next('/login'); // 重定向到登录页
} else {
next(); // 放行
}
});
全局后置守卫 (afterEach
)
afterEach
是路由跳转之后执行的事件。- 可以用作跳转路由后更改网页名。
在meta
中配置title
:
js
{
path: '/home',
name: 'home',
component: () => import('../views/Home.vue'),
meta: { title:'主页' },
},
全局后置路由守卫------------初始化的时候被调用、每次路由切换之后被调用
js
router.afterEach((to, from) => {
document.title = to.meta.title || '默认名' //修改网页的title,需要在meta中配置
});
独享路由守卫
- 在单个路由配置中定义的
beforeEnter
守卫。 - 独享路由守卫只有前置没有后置。
js
{
path: '/',
name: 'Home',
component: () => import('../views/Home.vue'),
beforeEnter: (to, from, next) => {
if (!isAuthenticated) {//未登录
next('/login'); // 重定向到登录页
} else {
next(); // 放行
}
}
},
组件内守卫
- 这些守卫可以在组件内部的路由发生变化时调用。
- 独享路由守卫只有前置没有后置,直接写在.vue文件中。
js
//通过路由规则,进入该组件时被调用
beforeRouteEnter(to,from,next) {
if (!isAuthenticated) {//未登录
next('/login'); // 重定向到登录页
} else {
next(); // 放行
}
},
//通过路由规则,离开该组件时被调用
beforeRouteLeave(to,from,next) {
next()
}
最后
看到这里希望你对Vue Router已经有了更全面的认识,总的来说,Vue Router 是前端学习的重要一步。希望你能够充分理解和利用 Vue Router 的强大功能,为你的Vue项目带来更加出色的用户交互体验。祝学习愉快!
已将学习代码上传至 github,欢迎大家学习指正!
技术小白记录学习过程,有错误或不解的地方还请评论区留言,如果这篇文章对你有所帮助请 "点赞 收藏+关注" ,感谢支持!!