携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第29天,点击查看活动详情
接上一篇 从创建vue项目到路由基础
获取练习完整代码 gitee.com/cj_23756590…
编程式导航
router.push
<router-link>路由导航实际上调用的就是 router.push 方法,在Vue实例中,可以通过 $router 访问路由实例,因此可以调用 this.$router.push,这个方法会向 history 栈添加一个新的记录,所以点击后退按钮,会回到上一页。
在homeview组件中
<button @click="toLogin">登录</button>
methods: {
toLogin() {
//字符串形式
this.$router.push("/login");
//对象形式
this.$router.push({
path: "/login",
});
//query传参
this.$router.push({
path: "/login",
query: { name: "jiaji", age: 20 },
});
//params传参,不能再使用path,需要使用name
this.$router.push({
name: "login",
params: { name: "jiaji", age: 20 },
});
},
},
router.replace
和 router.push 不同的是不会产生历史记录,通过该方法跳转页面后,点击后退会回到浏览器首页。
methods: {
toLogin() {
//字符串形式
this.$router.replace("/login");
},
},
router.go(n)
该方法会接收一个整数参数,在历史记录中前进或者后退 n 步。
// 下一页,等同于 history.forward()
router.go(1)
// 上一页,等同于 history.back()
router.go(-1)
// 前进 3 个页面
router.go(3)
// 如果 history 记录不够用,就没有任何反应
router.go(-100)
router.go(100)
嵌套路由
在 views 文件夹下创建两个组件:aaView.vue、bbView.vue,现在在 home 路由中有两个子路由,分别通过 home/aa 和 home/bb 访问。
在两个组件中分别添加:
<template>
<h1>aa</h1>
</template>
<template>
<h1>bb</h1>
</template>
在index.js文件中:
import aaView from "../views/aaView.vue";
import bbView from "../views/bbView.vue";
const routes = [
{
path: "/",
name: "home",
props: true,
component: HomeView,
children: [
{
path: "/aa",
name: "aa",
component: aaView,
},
{
path: "/bb",
name: "bb",
component: bbView,
},
],
},
]
在homeview组件中添加:
<router-view></router-view>
在一个页面中有多个子路由时就需要使用嵌套路由,运行项目,切换地址 http://localhost:8080/#/home/aa 和 http://localhost:8080/#/home/bb 就能访问两个子路由页面了。
路由元信息
定义路由时可以配置 meta 属性,是一个对象,讲一些静态信息可以挂在 meta 上跟着路由传递。
给之前的每个路由记录添加上 meta 属性
{
path: "/",
name: "home",
props: true,
component: HomeView,
meta: { title: "Home" },
},
{
path: "/login",
name: "login",
component: LoginView,
meta: { title: "Login" },
},
……
现在 route 对象上就有一个 meta 属性,在下一节会使用它。
导航守卫
导航守卫就是路由发生变化时执行的一些方法,然后在这些方法中可以做自己想做的事情。分为 全局守卫,路由独享守卫,组件守卫
全局守卫
全局前置守卫
使用 router.beforeEach 注册一个全局前置守卫:
在 index.js 文件中:
/**
* @description: 全局前置守卫
* @param {*} to 要进入的路由对象
* @param {*} from 离开的路由对象
* @param {*} next() 传入的参数有四种情况,为空时执行下一个导航守卫方法;false时中断当前的导航;如果是个路径,就跳转到指定的路由;如果是个error实例,导航终止并把实例传给 router.onError()回调
* @return {*}
*/
router.beforeEach((to, from, next) => {
console.log(from);
document.title = to.meta.title;
next();
});
当一个导航触发时,全局前置守卫按照创建顺序调用。守卫是异步解析执行,此时导航在所有守卫 resolve 完之前一直处于 等待中。
全局解析守卫
用 router.beforeResolve 注册一个全局解析守卫。这和 router.beforeEach 类似,区别是在导航被确认之前,同时在所有组件内守卫和异步路由组件被解析之后,解析守卫就被调用。
全局后置钩子
用 router.afterEach 可以注册全局后置钩子,钩子没有 next 参数,也不会改变导航本身:
router.afterEach((to, from) => {
// ...
})
路由独享守卫
在路由配置上直接定义 beforeEnter 守卫:
routes: [
{
path: "/",
name: "home",
props: true,
component: HomeView,
meta: { title: "Home" },
beforeEnter: (to, from, next) => {
console.log(from);
if (from.name === null) {
next("/login");
} else {
next();
}
},
}
]
如果是第一次进入home页面,就跳转到login页面
组件守卫
export default {
beforeRouteEnter(to, from, next) {
// 在渲染该组件的对应路由被 confirm 前调用
// 不能获取组件实例 `this`,因为当守卫执行前,组件实例还没被创建
},
beforeRouteUpdate(to, from, next) {
// 在当前路由改变,但是该组件被复用时调用
// 举例来说,对于一个带有动态参数的路径 /foo/:id,在 /foo/1 和 /foo/2 之间跳转的时候。
// 可以访问组件实例 `this`
},
beforeRouteLeave(to, from, next) {
// 导航离开该组件的对应路由时调用
// 可以访问组件实例 `this`
}
}
完整的导航解析流程
这里直接copy文档了
- 导航被触发。
- 在失活的组件里调用
beforeRouteLeave守卫。 - 调用全局的
beforeEach守卫。 - 在重用的组件里调用
beforeRouteUpdate守卫 (2.2+)。 - 在路由配置里调用
beforeEnter。 - 解析异步路由组件。
- 在被激活的组件里调用
beforeRouteEnter。 - 调用全局的
beforeResolve守卫 (2.5+)。 - 导航被确认。
- 调用全局的
afterEach钩子。 - 触发 DOM 更新。
- 调用
beforeRouteEnter守卫中传给next的回调函数,创建好的组件实例会作为回调函数的参数传入。