1. 介绍
Vue.js路由允许我们通过不同的url访问不同的内容
通过Vue.js可以实现多视图的单页Web应用(SPA)
参数或查询的改变并不会触发进入/离开的导航守卫,此时需要通过观察(watch);
$route 对象来应对这些变化,或使用 beforeRouteUpdate 的组件内守卫
2. vue-router使用步骤
2.1 下载安装vue-router
npm install --save vue-router
2.2 创建路由器对象
主模块: router/index.js
// 路由器对象模块
import Vue from 'vue'
// 1. 引入vue-router
import VueRouter from 'vue-router'
// 2. 引入各个路由组件
import Login from '../pages/Login/Login'
// 将一级的路由组件懒加载:设置路由懒加载
// 当使用了组件懒加载以后,MSite是一个返回路由组件的函数,只有在执行此函数时,才会加载路由组件
const MSite = () => import('../pages/MSite/MSite.vue')
// 3. 声明使用VueRouter
Vue.use(VueRouter);
// 4. 配置路由
const routes = [
{
path: '/',
redirect: '/msite',
// redirectc 表示如果找不到页面/ 就自动跳转到页面 /msite
},
{
path: '/msite',
// 路由组件函数,会在第一次请求对应的路由路径时,才会执行,因为使用了路由懒加载
component: MSite,
// 也可以简写为下面的方式,就不用在上面引入的
// component:()=>import('../pages/MSite/MSite.vue')
name:'msitePage' // 别名:使用的时候可以通过路由别名访问
meta: {
// 设置路由对象的参数
showFooter: true
}
},
{
path: '/shop',
component: Shop,
// 嵌套二级路由
children: [
{
path: '/shop/goods',
component: ShopGoods
},
{
path: '',
redirect: '/shop/goods'
}
]
},
{
path: '/login',
component: Login
},
]
// 创建 router 实例,然后传 `routes` 配置
export default new VueRouter({
mode: 'history',
// 5. 配置所有路由
routes
})
2.3 注册路由器 (在main.js里面)
import router from './router'
new Vue({
router
})
2.4 使用路由:router-link标签,用来生成路由组件标签
<!--1. 路径链接跳转-->
<!-- 方式一:直接使用path跳转 -->
<router-link to="/about">Go to XXX</router-link>
<!-- 方式二:使用name对象跳转 -->
<router-link :to="{name:'aboutPage'}">Go to XXX</router-link>
<!-- 2. router-link默认是解析为a标签,如果想要解析为li标签,设置tag属性-->
<router-link tag="li" to="/about">Go to XXX</router-link>
<!-- 3. 设置 链接激活时使用的 CSS 类名 active-class -->
<router-link to = "/about" active-class = "activeClass">XXX</router-link>
<!-- 4. router-view 用来显示当前路由组件的页面 -->
<!-- 路由匹配到的组件将渲染在这里 -->
<router-view></router-view>
3. 编程式路由导航
1) this.$router.push(path): 相当于点击路由链接(可以返回到当前路由界面)
2) this.$router.replace(path): 用新路由替换当前路由(不可以返回到当前路由界面)
3) this.$router.back(): 请求(返回)上一个记录路由
4) this.$router.go(-1): 请求(返回)上一个记录路由
5) this.$router.go(1): 请求下一个记录路由
3.1 请求(返回)上一个记录路由
this.$router.go(-1) == 跳转到上一次的浏览器页面(浏览器的回退按钮)
this.$router.back()
3.2 跳转到指定路由
3.3.1 保存路由记录 push
相当于点击路由链接,可以返回到当前路由界面,浏览器会有一个回退按钮
this.$router.push('/home')
this.$router.push({name:'homePage'})
3.3.2 不保存路由记录 replace
用新路由替换当前路由,不可以返回到当前路由界面
导航后不会留下 history 记录
this.$router.replace(path)
4. 缓存路由组件对象
默认情况下,当切换路由组件对象时,路由组件对象会死亡释放,再次切换回来时是重新创建的
如果可以缓存路由组件对象, 可以提高用户体验
<keep-alive>
<router-view></router-view>
</keep-alive>
5. 路由参数的传递
案例设置路的由对象如下:
{
path: '/loginPage', // path路径
name: 'loginLink', // 路由别名
component: login
}
5.1 方法一:编程式导航传递参数
5.1.1 params传参
注意:使用这种方式传递的参数,如果在目标页面刷新是会出错的
// 设置参数(路由别名跳转):
this.$router.push({ name: 'loginLink', params: { userId: 123 }})
// 接收参数:params
this.$route.params.userId
5.1.2 query传参
// 设置参数(路由路径跳转):
this.$router.push({ path: '/loginPage', query: { userId: 123 }});
// 接收参数:query
this.$route.query.userId
5.2 方法二:声明式的导航 <router-link> 传参
5.2.1 路由属性携带参数
这种是params传参的方式,目标页面没有 ?
// 1. 配置路由
{
path: '/loginPage/:userID', // 传递参数userID,采用占位符的方式
name: 'loginLink', // 路由别名
component: login
}
// 2. 路由router-link设置参数值
<router-link :to="'/loginPage/'+json.id">{{json.id}}</router-link>
// 3. 组件中获取参数
this.$route.params.userID
5.2.2 router-link设置参数
// 1. 通过 name别名的方式 设置参数:params传参
<router-link :to="{ name: 'loginLink', params: { userId: 1111}}">跳转页面</router-link>
this.$route.params.userId(接收参数)
// 2. 通过 path路径的方式 设置参数:query传参
<router-link :to="{ path: '/stype/details', query: { userId: 1111}}">跳转页面</router-link>
this.$route.query.userId(接收参数)
// 另外一种方式:query传参
<router-link :to="`/stype/details?id=`{{item.id}}">跳转页面</router-link>
// 接收参数
this.$route.query.id
6. 导航守卫
6.1 介绍
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航
注意: 参数或查询的改变并不会触发进入/离开的导航守卫。你可以通过观察
$route对象来应对这些变化,或使用beforeRouteUpdate的组件内守卫
6.2 全局前置守卫
使用 router.beforeEach 注册一个全局前置守卫:当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中
确保
next函数在任何给定的导航守卫中都被严格调用一次。它可以出现多于一次,但是只能在所有的逻辑路径都不重叠的情况下,否则钩子永远都不会被解析或报错
const router = new VueRouter({ ... })
router.beforeEach((to, from, next) => {
// ...
})
每个守卫接收的参数说明:
-
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的toprop 或router.push中的选项next(error): (2.4.0+) 如果传入next的参数是一个Error实例,则导航会被终止且该错误会被传递给router.onError()注册过的回调
案例展示:在用户未能验证身份时重定向到 /login
// BAD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
// 如果用户未能验证身份,则 `next` 会被调用两次
next()
})
// GOOD
router.beforeEach((to, from, next) => {
if (to.name !== 'Login' && !isAuthenticated) next({ name: 'Login' })
else next()
})
6.3 全局解析守卫
用 router.beforeResolve 注册一个全局守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用
6.4 全局后置钩子
你也可以注册全局后置钩子,然而和守卫不同的是,这些钩子不会接受 next 函数也不会改变导航本身
router.afterEach((to, from) => {
// ...
})
6.5 路由独享的守卫
可以在路由配置上直接定义 beforeEnter 守卫
const router = new VueRouter({
routes: [
{
path: '/foo',
component: Foo,
beforeEnter: (to, from, next) => {
// ...
}
}
]
})
6.6 完整的导航解析流程
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入