vue-router
是Vue.js
官方路由。它与Vue.js
核心深度集成,让用Vue
构建单页应用(SPA)变得非常容易。
vue-router
是基于路由和组件的。路由用于设定访问路径, 将路径和组件映射起来。
因此在vue-router
的单页面应用中, 页面的路径的改变就是组件的切换。
前端路由通过URL
的hash
做到URL
和内容进行映射。
URL
的hash
也就是锚点(#
), 本质上是改变window.location的href
属性。
hash
的优势就是兼容性更好,在老版IE
中都可以运行,但是缺陷是有一个#
,显得不像一个真实的路径。
npm install vue-router
创建路由需要映射的组件(打算显示的页面)
通过createRouter
创建路由对象,并且传入routes
和history
的模式:
routes
数组;hash
或者history
的模式;使用app
对象注册路由对象,使用use
方法;
路由使用: 通过
和
:
进行占位
进行路由切换Home.vue:
这是Home组件
About.vue
这是About组件
在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
作为路由模式。
在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')
告知路由的页面的显示位置。
App Content
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
to
属性: 是一个字符串,或者是一个对象
to="/home"
:to="{ path: '/home' }"
replace
属性:
replace
属性的话,当点击时,会调用 router.replace()
,而不是 router.push()
replace
替换模式跳转的话,历史不会被记录,点击浏览器返回不会返回到上一个路由active-class
属性:
设置激活a
元素后应用的class
,默认是router-link-active
复写这个css
类可以增加一些额外效果
如果重命名的话例如设置了 replace active-class="active"
,那么久这么复写:
exact-active-class
属性:
class
,默认是router-link-exact-active
随着业务逻辑越来越多,今后打包构建应用时,JavaScript
包会变得非常大,从而影响页面加载。
如果能把不同路由对应的组件分割成不同的代码块,当路由被访问的时候才加载对应组件,这样就会更加高效。
也可以提高首屏的渲染效率。
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
属性:路由信息中自定义的数据,添加后在需要的时候可以拿到
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
如果需要将给定匹配模式的路由映射到同一个组件,那么该如何做到呢?
例如,有一个 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
组件
用户123
用户456
如何在User.vue
中获取到对应的参数值:
在templat
中,直接通过$route.params
获取值;
User: {{ $route.params.id }}
在created
中,通过this.$route.params
获取值;
在setup
中,我们要使用vue-router
库给我们提供的一个hook
,即 useRoute
;
该Hook会返回一个Route
对象,对象中保存着当前路由相关的值;
可以编写一个NotFound.vue
这个组件,并配置路由规则,如果路由不匹配则显示这个组件。
NotFound.vue
NotFound: 您当前的路径{{ $route.params.pathMatch }}不正确, 请输入正确的路径!
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
属性即可。
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
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
提供的导航守卫主要用来通过跳转或取消的方式守卫导航
它的两个参数:
它的返回值:
string
类型的路径;path
、query
、params
等信息;可选的第三个参数:next
(不推荐使用)
Vue2
中是通过next
函数来决定如何进行跳转的;Vue3
中是通过返回值来控制的,不再推荐使用next
函数,这是因为开发中很容易调用多次next
;// 进行任何的路由跳转之前, 传入的beforeEach中的函数都会被回调
// 需求: 进入到订单(order)页面时, 判断用户是否登录(isLogin -> localStorage保存token)
// 情况一: 用户没有登录, 那么跳转到登录页面, 进行登录的操作
// 情况二: 用户已经登录, 那么直接进入到订单页面
router.beforeEach((to, from) => {
// 进入到订单页面时, 判断用户是否登录
const token = localStorage.getItem("token")
if (to.path === "/order" && !token) {
return "/login"
}
})
https://router.vuejs.org/zh/guide/advanced/navigation-guards.html
导航被触发。
在失活的组件里调用 beforeRouteLeave
守卫。
调用全局的beforeEach
守卫。
在重用的组件里调用beforeRouteUpdate
守卫(2.2+)。
在路由配置里调用 beforeEnter
。
解析异步路由组件。
在被激活的组件里调用 beforeRouteEnter
。
调用全局的 beforeResolve
守卫(2.5+)。
导航被确认。
调用全局的 afterEach
钩子。
触发 DOM
更新。
调用 beforeRouteEnter
守卫中传给 next
的回调函数,创建好的组件实例会作为回调函数的参数传入。
有时候希望通过代码来完成页面的跳转,比如点击的是一个按钮时就进行页面跳转。
使用OptionsAPI
时
this.$router.push( '/profile')
//或者
this.$router.push({
path: '/profile'
})
可以传入字符串或者对象。
使用setup
语法糖加上CompositionAPI
时
1)设置参数
2)在About.vue中获取参数
About: {{ $route.query }}
使用push
的特点是压入一个新的页面,那么在用户点击返回时,上一个页面还可以回退。
但是如果我们希望当前页面是一个替换 操作,那么可以使用replace
,使用replace
的话,上个页面无法回退。
router
的go
方法:
router
的back
方法:通过调用 history.back()
回溯历史,相当于 router.go(-1
),和浏览器左上角的←效果一样
router
的forward
方法:通过调用 history.forward()
在历史中前进,相当于router.go(1)
,和浏览器左上角的→效果一样