vue--编程式导航到导航守卫

190 阅读4分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 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.vuebbView.vue,现在在 home 路由中有两个子路由,分别通过 home/aahome/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/aahttp://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文档了

  1. 导航被触发。
  2. 在失活的组件里调用 beforeRouteLeave 守卫。
  3. 调用全局的 beforeEach 守卫。
  4. 在重用的组件里调用 beforeRouteUpdate 守卫 (2.2+)。
  5. 在路由配置里调用 beforeEnter
  6. 解析异步路由组件。
  7. 在被激活的组件里调用 beforeRouteEnter
  8. 调用全局的 beforeResolve 守卫 (2.5+)。
  9. 导航被确认。
  10. 调用全局的 afterEach 钩子。
  11. 触发 DOM 更新。
  12. 调用 beforeRouteEnter 守卫中传给 next 的回调函数,创建好的组件实例会作为回调函数的参数传入。