Vue04-vue-router
vue-router
目前前端流行的三大框架, 都有自己的路由实现:
-
Angular:ngRouter
-
React:ReactRouter
-
Vue:vue-router
Vue Router 是 Vue.js 的官方路由:
它与 Vue.js 核心深度集成,让用 Vue.js 构建单页应用(SPA)变得非常容易。
vue-router是基于路由和组件的:路由用于设定访问路径, 将路径和组件映射起来;
在vue-router的单页面应用中, 页面路径的改变就是组件的切换。
01. 基本使用
1.1 安装Vue Router
npm install vue-router
1.2 使用步骤
使用vue-router的步骤:
-
第一步:创建路由需要映射的组件(打算显示的页面);
-
第二步:通过createRouter创建路由对象,并且传入routes和history模式;
配置路由映射: 组件和路径映射关系的routes数组;
创建基于hash或者history的模式;
-
第三步:使用app注册路由对象(use方法);
-
第四步:路由使用: 通过
<router-link>和<router-view>;
目录结构图:

router/index.js:

main.js:

app.vue:

02. router-link属性
router-link有很多属性可以配置:
-
to属性:是一个字符串,或者是一个对象;
-
replace属性:设置 replace 属性的话,当点击时,会调用 router.replace(),而不是 router.push();
-
active-class属性:设置激活a元素后应用的class,默认是router-link-active;
-
exact-active-class属性:链接精准激活时,应用于渲染的 的 class,默认是router-link-exact-active;
03. 路由懒加载
前面我们提到过,如果项目的业务逻辑很多,组件很多,当打包构建应用时,JavaScript 包会变得非常大,影响页面加载。
如果我们能把不同路由对应的组件分割成不同的代码块,然后当路由被访问的时候才加载对应组件,这样就能提高首屏的渲染效率;
其实这里还是我们前面讲到过的webpack的分包知识,而Vue Router默认就支持动态来导入组件:
这是因为component可以传入一个组件,也可以接收一个函数,该函数 需要返回一个Promise;

使用import导入,打包时会进行分包处理。

04. 其他属性
name属性:路由记录独一无二的名称;
meta属性:自定义的数据

05. 动态路由
很多时候我们需要将给定匹配模式的路由映射到同一个组件,
例如,我们可能有一个 User 组件,它应该对所有用户进行渲染,但是用户的ID是不同的,
在Vue Router中,我们可以在路径中使用一个动态字段来实现,我们称之为 路径参数。

在router-link中进行如下跳转:

如果在子组件中,需要用到路由中传递的值,可以通过$route.params.id来获取。


06. NotFound
对于那些没有匹配到的路由,我们通常会将之匹配到固定的某个页面 --> NotFount页面。
{
// abc/cba/nba
// path: "/:pathMatch(.*)*", // 这种写法会对路径进行解析,返回数组。
path: "/:pathMatch(.*)",
component: () => import("../Views/NotFound.vue")
}

我们可以通过 $route.params.pathMatch 获取传入的参数:
<template>
<div class="not-found">
<h2>NotFound: 您当前的路径{{ $route.params.pathMatch }}不正确, 请输入正确的路径!</h2>
</div>
</template>
<script setup>
</script>
<style scoped>
.not-found {
color: red;
}
</style>
07. 编程式导航
前面我们都是通过<router-link>进行路由跳转。
但有时候,我们也需要使用其他标签,比如span标签、button标签,来进行路由跳转。
应该怎么实现呢?需要通过事件来进行。
这种方式称之为“编程式导航”。
<template>
<div class="app">
<div class="nav">
<router-link to="/home" replace>首页</router-link>
<router-link to="/about" replace active-class="active">关于</router-link>
<!-- 其他元素跳转 -->
<span @click="homeSpanClick">首页</span>
<button @click="aboutBtnClick">关于</button>
</div>
<router-view></router-view>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
// 监听元素的点击
function homeSpanClick() {
// 跳转到【首页】
// router.push("/home") // 简单写法
router.push({
// name: "home"
path: "/home"
})
}
function aboutBtnClick() {
// 跳转到【关于】
router.push({
path: "/about",
query: {
name: "why",
age: 18
}
})
}
</script>
某些页面中,我们也会添加【返回】,或【向前】按钮。
让用户根据自己的浏览路径,实现向前跳转与向后跳转。
实现方法同样是拿到router对象。
- router.back():向后跳转
- router.forward():向前跳转
- go(delta):delta为跳转步数。正数表示向前跳转;负数表示向后跳转。
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function backBtnClick() {
// router.back()
// router.forward()
// go(delta)
// go(1) -> forward()
// go(-1) -> back()
router.go(-1)
}
</script>
08. 动态管理路由
某些情况下我们可能需要动态地添加路由,比如根据用户角色的不同、权限的不同,注册不同的路由,
这时候我们可以使用一个方法addRouter。
// 模拟管理员
let isAdmin = true
// 给管理员添加专属于管理员的路由
if (isAdmin) {
// 添加一级路由
router.addRoute({
path: "/admin",
component: () => import("../Views/Admin.vue")
})
// 添加二级路由,第一个参数传入父级路由的name
router.addRoute("home", {
path: "vip", // 注意,不用书写成 /home/vip
component: () => import("../Views/HomeVip.vue")
})
}
8.1 删除路由
删除路由的情景比较少,删除路由有三种方式:
- 添加name相同的路由,那么后者将会替换前者;
- 通过removeRouter方法,传入路由的名称;
- 通过addRouter方法的返回值回调;

8.2 路由的其他方法
- router.hasRouter():检查路由是否存在;
- router.getRoutes():获取一个包含所有路由记录的数组。
09. 导航守卫
对于某些页面,比如由【商场首页】跳转【个人中心】,在路由跳转之前,需要先验证用户是否已经登录了:
- 用户已经登录,则顺利跳转;
- 用户没有登录,则跳转到登录页面。
从某一路由跳转到另一路由,这个过程称之为“导航”;
而在导航前做逻辑判断,或者导航后执行某一逻辑,这种功能即称之为“导航守卫”,
vue-router 也提供了对应的导航守卫功能:
- 全局前置守卫beforeEach
- 全局解析守卫beforeResolve
- 全局后置守卫afterEach(全局后置钩子)
- ...
参考官网:https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
全局前置守卫
全局前置守卫beforeEach,传入一个函数,该函数在导航触发时会自动执行。
前置守卫:在跳转之前进行守卫。
router.beforeEach((to,from)=>{
console.log(to)
console.log(from)
// 获取登录凭证
const token = localStorage.getItem("token")
// 没有登录凭证,且将跳转的路由并非登录界面,
if (to.path !== "/login" && !token) {
return "/login"
// 对象写法
// return { name: 'Login' }
}
// return false
})
它有两个参数:
-
to:即将进入的路由Route对象;
-
from:即将离开的路由Route对象;
可以设置返回值:
-
false:取消当前导航;
-
不返回或者undefined:进行默认导航;
-
也可以返回一个路由地址,将跳转到该路由地址,就像你调用
router.push()一样。-
可以是一个string类型的路径;
-
可以是一个对象,对象中包含path、query、params等信息;
-
可选的第三个参数:next(不推荐使用)
在Vue2中我们是通过next函数来决定如何进行跳转的;
但是在Vue3中我们是通过返回值来控制的,不再推荐使用next函数,这是因为开发中很容易调用多次next;
全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身:
router.afterEach((to, from) => {
sendToAnalytics(to.fullPath)
})
它们对于分析、更改页面标题、声明页面等辅助功能以及许多其他事情都很有用。
它们也反映了 navigation failures 作为第三个参数:
router.afterEach((to, from, failure) => {
if (!failure) sendToAnalytics(to.fullPath)
})
路由独享的守卫
你可以直接在路由配置上定义 beforeEnter 守卫:
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: (to, from) => {
// reject the navigation
return false
},
},
]
beforeEnter 守卫 只在进入路由时触发,不会在 params、query 或 hash 改变时触发。例如,从 /users/2 进入到 /users/3 或者从 /users/2#info 进入到 /users/2#projects。它们只有在 从一个不同的 路由导航时,才会被触发。
你也可以将一个函数数组传递给 beforeEnter,这在为不同的路由重用守卫时很有用:
function removeQueryParams(to) {
if (Object.keys(to.query).length)
return { path: to.path, query: {}, hash: to.hash }
}
function removeHash(to) {
if (to.hash) return { path: to.path, query: to.query, hash: '' }
}
const routes = [
{
path: '/users/:id',
component: UserDetails,
beforeEnter: [removeQueryParams, removeHash],
},
{
path: '/about',
component: UserDetails,
beforeEnter: [removeQueryParams],
},
]
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫(2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫(2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。

浙公网安备 33010602011771号