Vue组合式API--路由的使用详解
Vue3中路由的使用
一、Vue路由的概述
vue-router
是Vue.js
官方路由。它与Vue.js
核心深度集成,让用Vue
构建单页应用(SPA)变得非常容易。
vue-router
是基于路由和组件的。路由用于设定访问路径, 将路径和组件映射起来。
因此在vue-router
的单页面应用中, 页面的路径的改变就是组件的切换。
前端路由通过URL
的hash
做到URL
和内容进行映射。
URL
的hash
也就是锚点(#
), 本质上是改变window.location的href
属性。
hash
的优势就是兼容性更好,在老版IE
中都可以运行,但是缺陷是有一个#
,显得不像一个真实的路径。
二、安装vue-router
npm install vue-router
三、vue-router路由的基本使用步骤
-
创建路由需要映射的组件(打算显示的页面)
-
通过
createRouter
创建路由对象,并且传入routes
和history
的模式:- 配置路由映射: 组件和路径映射关系的
routes
数组; - 创建基于
hash
或者history
的模式;
- 配置路由映射: 组件和路径映射关系的
-
使用
app
对象注册路由对象,使用use
方法; -
路由使用: 通过
<router-link>
和<router-view>
:<router-view>
进行占位<router-link>
进行路由切换
3.1 准备路由需要显示的组件
Home.vue:
<template>
<div class="about">
这是Home组件
</div>
</template>
<script setup>
</script>
About.vue
<template>
<div class="about">
这是About组件
</div>
</template>
<script setup>
</script>
3.2 通过createRouter创建路由对象
在router
目录下的index.js
中配置路由映射规则。
//1.1 引入创建路由的函数 以及采取的路由模式(hash还是history)
import { createRouter, createWebHashHistory} from 'vue-router'
//1.2 引入需要展示的组件
import Home from '../Views/Home.vue'
import About from '../Views/About.vue'
// 2 创建一个路由: 映射关系
const router = createRouter({
// 2.1 指定采用的路由模式: hash
history: createWebHashHistory(),
// 2.2 配置路由映射关系
routes: [
{ path: " /home", component: Home },
{ path: " /about", component: About }
]
})
export default router
history
和hash
两种方式最直观的区别就是浏览器地址栏上会不会带一个#
号。
一般来讲都会选用hash
作为路由模式。
3.3 使用app对象注册路由对象
在main.js
中拿到app
对象,再使用app
对象的use
方法去注册路由对象。
import { createApp } from 'vue'
import App from './App.vue'
import router from './router' // 1.引入路由映射的js文件
const app = createApp(App) // 2.拿到vue实例对象
app.use(router) // 3.注册引入的路由映射
app.mount('#app')
3.4 使用路由
告知路由的页面的显示位置。
<template>
<div class="app">
<h2>App Content</h2>
<div class="nav">
<router-link to="/home" replace>首页</router-link>
<!--
写法二:
<router-link :to="{ path: '/home' }" replace>首页</router-link>
-->
<router-link to="/about" replace active-class="active">关于</router-link>
</div>
<!-- router-view标签中就会显示当前路由对应的组件 -->
<router-view></router-view>
</div>
</template>
<script setup>
</script>
- 使用
router-link
标签会在页面上渲染出两个a
标签,跳转的路径就是to
属性指向的组件 router-view
标签会显示当前url
下的对应组件
四、设置路由的默认路径
默认情况下, 进入网站的首页,需要渲染网站首页的内容。
这时需要在routes
配置项下新增一个路由。
//1.1 引入创建路由的函数 以及采取的路由模式(hash还是history)
import { createRouter, createWebHashHistory} from 'vue-router'
//1.2 引入需要展示的组件
import Home from '../Views/Home.vue'
import About from '../Views/About.vue'
// 2 创建一个路由: 映射关系
const router = createRouter({
// 2.1 指定采用的路由模式: hash
history: createWebHashHistory(),
// 2.2 配置路由映射关系
routes: [
{ path: "/", redirect: "/home" }, //设置路由的默认路径
{ path: " /home", component: Home },
{ path: " /about", component: About }
]
})
export default router
五、router-link的其它属性
-
to
属性: 是一个字符串,或者是一个对象- 字符串示例:
to="/home"
- 对象示例:
:to="{ path: '/home' }"
- 字符串示例:
-
replace
属性:- 设置
replace
属性的话,当点击时,会调用router.replace()
,而不是router.push()
- 直观的区别就是
replace
替换模式跳转的话,历史不会被记录,点击浏览器返回不会返回到上一个路由
- 设置
-
active-class
属性:-
设置激活
a
元素后应用的class
,默认是router-link-active
复写这个
css
类可以增加一些额外效果<style> .router-link-active { color: red; font-size: 20px; } </style>
-
如果重命名的话例如设置了
replace active-class="active"
,那么久这么复写:<style> .active { color: red; font-size: 20px; } </style>
-
-
exact-active-class
属性:- 链接精准激活时,应用于渲染的 的
class
,默认是router-link-exact-active
- 主要用于路由嵌套中的精准匹配
- 链接精准激活时,应用于渲染的 的
六、路由懒加载
6.1 路由懒加载的作用
随着业务逻辑越来越多,今后打包构建应用时,JavaScript
包会变得非常大,从而影响页面加载。
如果能把不同路由对应的组件分割成不同的代码块,当路由被访问的时候才加载对应组件,这样就会更加高效。
也可以提高首屏的渲染效率。
6.2 具体操作
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
path: "/",
redirect: "/home"
},
{
path: "/home",
component: () => import("../Views/Home.vue"), //使用import函数导入组件
},
{
path: "/about",
component: () => import("../Views/About.vue"),
},
]
})
export default router
component
可以传入一个组件,也可以接收一个函数,该函数 需要放回一个Promise。
而import函数就是返回一个Promise
,并且webpack
会以import
为分包节点,达到路由懒加载的目的。
七、路由的name和meta属性
-
name
属性:记录路由独一无二的名称 -
meta
属性:路由信息中自定义的数据,添加后在需要的时候可以拿到
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
name: "home",
path: "/home",
component: () => import("../Views/Home.vue"),
meta: {
name: "why",
age: 18
},
}
]
})
export default router
八、动态路由
8.1 配置和使用动态路由
如果需要将给定匹配模式的路由映射到同一个组件,那么该如何做到呢?
例如,有一个 User 组件,它对所有用户进行渲染,但是用户的ID是不同的;
貌似使用/user/123
和user/456
是没法跳转到同一个路由的。
Vue
中的解决方案是,在Vue Router
中,在路径中使用一个动态字段来实现,我们称之为 路径参数;
import { createRouter, createWebHashHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
path: "/user/:id", //这里的:id就是一个路径参数
component: () => import("../Views/User.vue")
},
]
})
export default router
这样一来router-link
中怎么给id
的值都会显示User.vue
组件
<router-link to="/user/123">用户123</router-link>
<router-link to="/user/321">用户456</router-link>
8.2 获取动态路由的参数值
如何在User.vue
中获取到对应的参数值:
-
在
templat
中,直接通过$route.params
获取值;<template> <div class="user"> <!-- 在模板中获取到id --> <h2>User: {{ $route.params.id }}</h2> </div> </template>
-
在
created
中,通过this.$route.params
获取值;<script> export default { created(){ console.log(this.$route.params.id) }, } </script>
-
在
setup
中,我们要使用vue-router
库给我们提供的一个hook
,即useRoute
;
该Hook会返回一个Route
对象,对象中保存着当前路由相关的值;<script setup> import { useRoute, onBeforeRouteUpdate } from 'vue-router' // 第一次的时候执行这个函数获取路由参数 const route = useRoute() console.log(route.params.id) // 获取route跳转id,即在 /user/123跳转到/user/456时会触发下面的函数,获取到起点和终点的参数 // 这个方式用的很少,基本不会有这种需求,了解即可 onBeforeRouteUpdate((to, from) => { console.log("from:", from.params.id) console.log("to:", to.params.id) }) </script>
九、关于没有匹配到的路由路径的处理
可以编写一个NotFound.vue
这个组件,并配置路由规则,如果路由不匹配则显示这个组件。
NotFound.vue
<template>
<div class="not-found">
<!-- 可以通过 $route.params.pathMatch获取到传入的参数 -->
<h2>NotFound: 您当前的路径{{ $route.params.pathMatch }}不正确, 请输入正确的路径!</h2>
</div>
</template>
<script setup>
</script>
<style scoped>
.not-found {
color: red;
}
</style>
router目录下的index.js
import { createRouter, createWebHashHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
path: "/:pathMatch(.*)*",
component: () => import("../Views/NotFound.vue")
}
]
})
export default router
/:pathMatch(.*)
和/:pathMatch(.*)*
的区别:
- 使用
/:pathMatch(.*)
语法时,获取到的参数为/user/123
- 使用
/:pathMatch(.*)*
语法时,获取到的参数为["user","123"]
十、路由嵌套
如果Home
页面本身也存在多个组件之间来回切换,这时候就可以使用路由嵌套。
只需要配置children
属性即可。
10.1 路由嵌套基本配置
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
path: "/",
redirect: "/home" //配置一级路由的默认首页
},
{
name: "home",
path: "/home",
component: () => import("../Views/Home.vue"),
meta: {
name: "张三",
age: 18
},
children: [
{
path: "/home",
redirect: "/home/recommend" //配置二级路由的默认首页
},
{
path: "recommend",
component: () => import("../Views/HomeRecommend.vue")
},
{
path: "ranking", // /home/ranking
component: () => import("../Views/HomeRanking.vue")
}
]
},
]
})
export default router
10.2 路由嵌套动态配置
import { createRouter, createWebHashHistory, createWebHistory } from 'vue-router'
// 创建一个路由: 映射关系
const router = createRouter({
// 指定采用的模式: hash
history: createWebHashHistory(),
// 映射关系
routes: [
{
path: "/",
redirect: "/home" //配置一级路由的默认首页
},
{
name: "home",
path: "/home",
component: () => import("../Views/Home.vue"),
},
]
})
// 如果是vip的话 就动态添加一个home下的二级路由
// 这个home是上面routes中配置的name属性
let isVip = true
if (isVip) {
router.addRoute("home", {
path: "vip",
component: () => import("../Views/HomeVip.vue")
})
}
export default router
十一、删除路由
-
添加一个
name
相同的路由- 因为
name
属性时唯一的,后面添加的相同name
的路由会覆盖之前的
router.addRoute({ path: '/about' , name: 'about' , component: About })
- 因为
-
通过
removeRoute
方法,传入路由的名称router.removeRoute( ' about')
-
通过
addRoute
方法的返回值回调const removeRoute = router.addRoute({ path:'/about', name:'about', component:About }) removeRoute()
十二、路由的其他方法
router.hasRoute()
:检查路由是否存在。router.getRoutes()
:获取一个包含所有路由记录的数组。
十三、路由守卫
vue-router
提供的导航守卫主要用来通过跳转或取消的方式守卫导航
13.1 全局的前置守卫beforeEach参数和返回值说明
-
它的两个参数:
- to:即将进入的路由Route对象;
- from:即将离开的路由Route对象;
-
它的返回值:
- false:取消当前导航;
- 不返回或者undefined:进行默认导航;
- 返回一个路由地址:
- 可以是一个
string
类型的路径; - 可以是一个对象,对象中包含
path
、query
、params
等信息;
- 可以是一个
-
可选的第三个参数:
next
(不推荐使用)- 在
Vue2
中是通过next
函数来决定如何进行跳转的; - 在
Vue3
中是通过返回值来控制的,不再推荐使用next
函数,这是因为开发中很容易调用多次next
;
- 在
13.2 beforeEach的使用场景之一:登录守卫
// 进行任何的路由跳转之前, 传入的beforeEach中的函数都会被回调
// 需求: 进入到订单(order)页面时, 判断用户是否登录(isLogin -> localStorage保存token)
// 情况一: 用户没有登录, 那么跳转到登录页面, 进行登录的操作
// 情况二: 用户已经登录, 那么直接进入到订单页面
router.beforeEach((to, from) => {
// 进入到订单页面时, 判断用户是否登录
const token = localStorage.getItem("token")
if (to.path === "/order" && !token) {
return "/login"
}
})
13.3 路由守卫官方文档
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
13.4 完整的路由导航解析流程
-
导航被触发。
-
在失活的组件里调用
beforeRouteLeave
守卫。 -
调用全局的
beforeEach
守卫。 -
在重用的组件里调用
beforeRouteUpdate
守卫(2.2+)。 -
在路由配置里调用
beforeEnter
。 -
解析异步路由组件。
-
在被激活的组件里调用
beforeRouteEnter
。 -
调用全局的
beforeResolve
守卫(2.5+)。 -
导航被确认。
-
调用全局的
afterEach
钩子。 -
触发
DOM
更新。 -
调用
beforeRouteEnter
守卫中传给next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
十四、编程式路由跳转
12.1 基本使用
有时候希望通过代码来完成页面的跳转,比如点击的是一个按钮时就进行页面跳转。
-
使用
OptionsAPI
时this.$router.push( '/profile') //或者 this.$router.push({ path: '/profile' })
可以传入字符串或者对象。
-
使用
setup
语法糖加上CompositionAPI
时<template> <div class="app"> <div class="nav"> <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({ path: "/home" // name: "home" 使用name方式也可以,不过不推荐 }) } function aboutBtnClick() { // 跳转到关于 router.push({ path: "/about" }) } </script>
12.2 使用query来传递参数
1)设置参数
<template>
<div class="app">
<div class="nav">
<button @click="aboutBtnClick">关于</button>
</div>
<router-view></router-view>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function aboutBtnClick() {
// 跳转到关于
router.push({
path: "/about",
query: {name: "why",age: 18}
})
}
</script>
2)在About.vue中获取参数
<template>
<div class="about">
<h2>About: {{ $route.query }}</h2>
</div>
</template>
12.3 编程式路由跳转时push和replace的如别
使用push
的特点是压入一个新的页面,那么在用户点击返回时,上一个页面还可以回退。
但是如果我们希望当前页面是一个替换 操作,那么可以使用replace
,使用replace
的话,上个页面无法回退。
12.4 编程式路由控制页面前进或者后退的方式
router
的go
方法:
<template>
<div class="about">
<button @click="backBtnClick">返回</button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function backBtnClick() {
//·向前移动一条记录,与·router.forward()·相同
router.go(1)
//·返回一条记录,与router.back()·相同
router.go(-1)
//·前进·3·条记录
router.go(3)
//·如果没有那么多记录,静默失败
router.go(-100)
router.go (100)
}
</script>
router
的back
方法:
通过调用 history.back()
回溯历史,相当于 router.go(-1
),和浏览器左上角的←效果一样
<template>
<div class="about">
<button @click="backBtnClick">返回</button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function backBtnClick() {
router.back()
}
</script>
router
的forward
方法:
通过调用 history.forward()
在历史中前进,相当于router.go(1)
,和浏览器左上角的→效果一样
<template>
<div class="about">
<button @click="backBtnClick">返回</button>
</div>
</template>
<script setup>
import { useRouter } from 'vue-router'
const router = useRouter()
function backBtnClick() {
router.forward()
}
</script>
更多推荐
所有评论(0)