目录
简介
安装与基本使用
路由器的工作模式
嵌套路由
params传参和query传参
query传参
params传参
命名路由
路由组件传参(props配置)
对象模式
布尔模式
函数模式
router-link的replace属性
编程式路由/导航
缓存路由组件
路由守卫/导航守卫
全局守卫
独享守卫
组件内守卫
路由元信息
完整的导航解析流程
Vue-router是vue的一个插件库,专门用来实现SPA(single page web application,单页web应用)应用;
路由其实就是一组映射关系(key-value),key为路径,value可能是function或者component
2022年2月7日以后,vue-router的默认安装版本为版本4,即vue-router4只能用在vue3中,vue-router3才能用在vue2中;
npm install vue-router // 默认安装的是版本4
npm install vue-router@3 // 安装的是版本3
如果要在一个模块化工程中使用它,必须要通过Vue.use()明确的安装路由功能(Vue-router是个插件):
// router/index.js文件
import Vue from 'vue'
import Router from 'vue-router'
// 导入组件
import Login from '../view/gsys/Login'
// 应用路由插件
Vue.use(Router)
// 创建一个路由器
export default new Router({
routes: [{
path: '/login',
component: Login
}
]
})
// main.js文件
import Vue from 'vue'
import App from './App'
import router from './router'
new Vue({
el: '#app',
router,
components: { App },
template: ' '
})
// app.vue文件
//通过标签router-link组件来导航,to表示导航到的路径,active-class属性实现高亮样式,该标签默认会被渲染成一个标签
首页
// 路由出口----路由匹配到的组件将会被渲染在此处
注意:
- 路由组件通常存放于pages文件夹,一般组件一般存放于components文件夹;
- 通过切换组件,“隐藏”了的路由组件,默认是被销毁的,所以组件的生命周期函数皆不起作用了,需要的时候再去挂载;
- 每个组件都有自己的$route属性,里面存储的是自己的路由信息;
- 整个应用只有一个router,可通过组件的$router属性获取到;
- 常规参数只会匹配被/分割的URL片段中的字符。若想匹配任意路径,可以使用通配符(*)
{
// 会匹配所有路径
path: '*'
}
{
// 会匹配以 `/user-` 开头的任意路径
path: '/user-*'
}
注意使用通配符路由时,请确保路由的顺序是正确的,也就是说含有通配符的路由应该放到最后。路由{path: '*'}通常用于客户端404错误页;
当使用一个通配符时,$route.params内会自动添加一个名为pathMatch参数,它包含了URL通过通配符被匹配到的部分:
// 给出一个路由 { path: '/user-*' }
this.$router.push('/user-admin')
this.$route.params.pathMatch // 'admin'
// 给出一个路由 { path: '*' }
this.$router.push('/non-existing')
this.$route.params.pathMatch // '/non-existing'
路由器的工作模式
vue-router默认hash模式(url中#及其后面的内容就是hash值)----使用url的hash来模拟一个完整的url,于是当url改变时,页面不会被重新加载;且兼容性较好,但缺点是不美观~
如果不想要很丑的hash,可使用history模式,这种美观,但兼容性较差,更要命的是若后台未配置,则直接访问如http://oursite.com/user/id会返回404;配置history模式代码如下:
const router = new VueRouter({
mode: 'history',
routes: [...]
})
嵌套路由
配置嵌套路由,使用children配置项:
// 配置路由规则
routes: [{
path: '/login',
component: Login
children: [
{
path: 'user',
component: User
}
]
}]
// 跳转
用户
注意:
配置子路径时,path中不需要加/(因为以/开头的嵌套路径会被当作根路径,可让我们充分的使用嵌套组件而无需设置嵌套的路径),跳转中to的路径要加上!
params传参和query传参
query传参
query传参不会破坏路由规则,只需将参数配置在跳转标签中即可;
// 跳转
// to的字符串写法
用户
// to的对象写法
用户
// 接收参数
$route.query.id
$route.query.name
params传参
params传参要破坏路由配置规则,在path中加入:要传入的参数;
// 配置路由规则
routes: [{
path: '/login',
component: Login
children: [
{
path: 'user/:id/:name',
component: User,
name: 'user' // 命名路由
}
]
}]
// 跳转
// to的字符串写法
用户
// to的对象写法
用户
并且使用params传参的对象形式时,子页面的router-link不允许使用path了,必须要使用命名路由name。
// 接收参数
$route.params.id
$route.params.name
可看另一篇文章总结params传参与query传参总结
命名路由
设置命名路由后,就可在设置跳转路由地址的地方使用,将长长的path路径替代为name属性:
const router = new VueRouter({
routes: [
{
path: '/user/address',
name: 'address',
component: Address
}
]
})
要链接到一个命名路由,可以改router-link的to属性传一个对象;
// 简化前
地址
// 简化后
地址
路由组件传参(props配置)
在组件中使用$route会使之与其对应路由形成高度耦合,从而使组件只能在某些特定的url上使用,限制了其灵活性,可使用props将组件和路由解耦,有三种方式:
对象模式
若props值是对象,则该对象中所有的key-value的组合最终都会通过props传给组件,这种方式一般用来传递静态参数;
const router = new VueRouter({
routes: [
{
path: '/promotion/from-newsletter',
component: Promotion,
props: { id: 12 }
}
]
})
布尔模式
若props值是布尔值,若布尔值为true,则就会将路由收到的所有params参数通过props传给组件(适用于params传参);
函数模式
若props值为函数,则该函数返回的对象中每一组key-value值都会通过props传给组件;
const router = new VueRouter({
routes: [
{
path: '/search',
component: SearchUser,
props(route) {
return {
id: route.query.id
}
}
]
})
三种方式对应组件使用:
{{groupId}}
router-link的replace属性
该属性是用来控制路由跳转时操作浏览器历史记录的模式;
浏览器的历史记录有两种写入方式:分别为push和replace,其中push是追加历史记录,replace是替换当前记录,路由跳转时默认为push;
使用如下代码即可开启replace模式,开启了replace模式后,则该页面在浏览器前进后退中则不会出现,即点击浏览器后退按钮后,不会再返回之前的设置了replace属性的页面;
首页
编程式路由/导航
除了 使用router-link标签创建a标签来定义导航链接,还可借助router的实例方法,通过编写代码来实现。使用$router.push或$router.replace实现路由跳转;
该对象的参数可以是一个字符串路径,或者是一个描述地址的对象;
// 字符串
this.$router.push('home')
// 对象
this.$router.push({ path: 'home' })
// 命名的路由
this.$router.push({ name: 'user', params: { userId: '123' }})
// 带查询参数,变成 /register?plan=private
this.$router.push({ path: 'register', query: { plan: 'private' }})
router.replace同理;
this.$router.forward() // 前进一步
this.$router.back() // 后退
this.$router.go(n) // 可前进(正数),可后退(负数)
缓存路由组件
前面说过,在切换路由组件时,默认会销毁前一个组件,但是有的时候,如果想保留前一页面中的内容,则不希望在前进页面的时候,将该页提交的内容全部删除掉,这种场景下,可通过缓存路由keep-alive来实现;
在路由出口处设置即可:
若想仅对某些页面缓存,则可设置include属性,参数值是设置缓存的页面/组件名;
缓存的页面多的话,要设置成数组形式:
路由守卫/导航守卫
路由守卫用于对路由进行权限控制,主要分为全局守卫/独享守卫与组件内守卫;
全局守卫
全局守卫分为全局前置守卫/全局解析守卫/全局后置守卫;
- 全局前置守卫
全局前置守卫router.beforeEach在路由初始化时执行,每次路由切换前执行。接收三个参数:
to: Route -----
即将要进入的目标路由对象
from: Route -----
当前导航正要离开的路由
next: Function ------
一定要调用该方法来 resolve 这个钩子。执行效果依赖 next
方法的调用参数。若不调用这个方法,则路由导航就会被拦截;
next()
: 进行管道中的下一个钩子。如果全部钩子执行完了,则导航的状态就是 confirmed (确认的)。
next(false)
: 中断当前的导航。如果浏览器的 URL 改变了 (可能是用户手动或者浏览器后退按钮),那么 URL 地址会重置到 from
路由对应的地址。
next('/')
或者 next({ path: '/' })
: 跳转到一个不同的地址。当前的导航被中断,然后进行一个新的导航。你可以向 next
传递任意位置对象,且允许设置诸如 replace: true
、name: 'home'
之类的选项以及任何用在router-link的to prop或router.push中的选项。
next(error)
: (2.4.0+) 如果传入 next
的参数是一个 Error
实例,则导航会被终止且该错误会被传递给router.onError()注册过的回调。
确保next函数在任何给定的路由守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错;
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
-
全局解析守卫
在版本2.5.0+可以使用router.beforeResolve注册一个全局守卫。这和router.beforeEach类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由被解析之后,解析守卫就被调用;
- 全局后置守卫
全局后置守卫router.aftereach用于初始化的时候被调用,每次路由切换之后被调用,与前两个守卫不同的是,它不会接收next函数,并且也不会改变导航本身,因为他已经切换完了;
独享守卫
可在路由配置上直接定义beforeEnter守卫,用于对该路由进行权限控制;参数与全局前置守卫一样;
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
组件内守卫
组件内守卫是指定义在组件内,在路由跳转至组件内部或离开组件的时候的权限控制;有三种beforeRouterEnter/beforeRouterUpdate(2.2新增)/beforeRouteLeave
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不!能!获取组件实例 `this`
// 因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候,
// 由于会渲染同样的 Foo 组件,因此组件实例会被复用。而这个钩子就会在这个情况下被调用。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
离开守卫通常用于禁止用户在还未保存修改前突然离开,该导航可以通过next(false)来取消;
beforeRouteLeave (to, from, next) {
const answer = window.confirm('Do you really want to leave? you have unsaved changes!')
if (answer) {
next()
} else {
next(false)
}
}
路由元信息
可在需要权限校验的路由配置项上配置meta元信息,如:
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
children: [
{
path: 'bar',
component: Bar,
// a meta field
meta: { requiresAuth: true }
}
]
}
]
})
可通过$route.meta.xxx进行访问,也可以通过$route.matched来检查路由记录中的meta字段(一个路由匹配到的所有路由记录都会暴露成$route对象的$route.matched数组)。
router.beforeEach((to, from, next) => {
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
if (!auth.loggedIn()) {
next({
path: '/login',
query: { redirect: to.fullPath }
})
} else {
next()
}
} else {
next() // 确保一定要调用 next()
}
})
完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave
守卫。
- 调用全局的
beforeEach
守卫。
- 在重用的组件里调用
beforeRouteUpdate
守卫 (2.2+)。
- 在路由配置里调用
beforeEnter
。
- 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter
。
- 调用全局的
beforeResolve
守卫 (2.5+)。
- 导航被确认。
- 调用全局的
afterEach
钩子。
- 触发 DOM 更新。
- 调用
beforeRouteEnter
守卫中传给 next
的回调函数,创建好的组件实例会作为回调函数的参数传入。