Vue-router的钩子函数和组件生命周期的执行顺序总结。单独讨论Vue组件的生命周期会觉得非常的容易,但是一旦涉及到路由导航守卫,情况就变的复杂的多了,从技术原理来说无论是导航守卫还是组件生命周期都是函数,只是这些函数执行的时间不一,触发函数执行的条件也不一。
使用VueCli4搭建的初始模板,并做简单的修改:
Home组件:
<template> <div class="home"> <img alt="Vue logo" src="../assets/logo.png" /> <HelloWorld msg="Welcome to Your Vue.js App" /> </div> </template> <script> // @ is an alias to /src import HelloWorld from "@/components/HelloWorld.vue"; export default { name: "Home", components: { HelloWorld, }, methods: { randChange() { this.shuju = Math.floor(Math.random() * 10); }, }, beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 console.log("执行了 Home 组件 beforeRouteEnter"); next(); }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 可以访问组件实例 `this` console.log("执行了 Home 组件 beforeRouteUpdate"); next(); }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` console.log("执行了 Home 组件 beforeRouteLeave"); next(); }, //组件生命周期 beforeCreate() { console.log("执行了 Home 组件 beforeCreate 生命周期"); }, created() { console.log("执行了 Home 组件 Created 生命周期"); }, beforeMount() { console.log("执行了 Home 组件 beforeMount 生命周期"); }, mounted() { console.log("执行了 Home 组件 mounted 生命周期"); }, beforeUpdate() { console.log("执行了 Home 组件 beforeUpdate 生命周期"); }, updated() { console.log("执行了 Home 组件 updated 生命周期"); }, beforeDestroy() { console.log("执行了 Home 组件 beforeDestroy 生命周期"); }, destroyed() { console.log("执行了 Home 组件 destroyed 生命周期"); }, }; </script>
About组件:
<template> <div class="about"> <h1>This is an about page</h1> </div> </template> <script> export default { beforeRouteEnter(to, from, next) { // 在渲染该组件的对应路由被 confirm 前调用 // 不!能!获取组件实例 `this` // 因为当守卫执行前,组件实例还没被创建 console.log("执行了 About 组件 beforeRouteEnter"); next(); }, beforeRouteUpdate(to, from, next) { // 在当前路由改变,但是该组件被复用时调用 // 可以访问组件实例 `this` console.log("执行了 About 组件 beforeRouteUpdate"); next(); }, beforeRouteLeave(to, from, next) { // 导航离开该组件的对应路由时调用 // 可以访问组件实例 `this` console.log("执行了 About 组件 beforeRouteLeave"); next(); }, //组件生命周期 beforeCreate() { console.log("执行了 About 组件 beforeCreate 生命周期"); }, created() { console.log("执行了 About 组件 Created 生命周期"); }, beforeMount() { console.log("执行了 About 组件 beforeMount 生命周期"); }, mounted() { console.log("执行了 About 组件 mounted 生命周期"); }, beforeUpdate() { console.log("执行了 About 组件 beforeUpdate 生命周期"); }, updated() { console.log("执行了 About 组件 updated 生命周期"); }, beforeDestroy() { console.log("执行了 About 组件 beforeDestroy 生命周期"); }, destroyed() { console.log("执行了 About 组件 destroyed 生命周期"); }, }; </script>
router/index.js 路由配置文件:
import Vue from "vue"; import VueRouter from "vue-router"; import Home from "../views/Home.vue"; Vue.use(VueRouter); const routes = [ { path: "/", name: "Home", component: Home, // 路由独享守卫 beforeEnter: (to, from, next) => { console.log("执行了 Home组件 路由独享守卫 beforeEnter"); next(); }, }, { path: "/about", name: "About", // route level code-splitting // this generates a separate chunk (about.[hash].js) for this route // which is lazy-loaded when the route is visited. component: () => import(/* webpackChunkName: "about" */ "../views/About.vue"), // 路由独享守卫 beforeEnter: (to, from, next) => { console.log("执行了 About 组件 路由独享守卫 beforeEnter"); next(); }, }, ]; const router = new VueRouter({ mode: "history", base: process.env.BASE_URL, routes, }); //全局前置守卫 router.beforeEach((to, from, next) => { console.log("执行了 全局前置守卫 beforeEach"); next(); }); // 全局解析守卫 router.beforeResolve((to, from, next) => { console.log("执行了 全局解析守卫 beforeResolve"); next(); }); // 全局后置钩子 router.afterEach((to, from) => { console.log("执行了 全局后置钩子 afterEach"); }); export default router;
启动项目,并切换到console看输出状态,然后再切换导航看控制台输出的内容。
假设从组件Home导航到组件About,则会经过以下几个路由的钩子函数和组件生命周期。会分为两种情况。
一 初始化第一个页面
无论是SPA还是MPA都会有一个默认的初始化首页。这个初始化页面会按顺序经过如下各种钩子:
导航钩子/组件生命周期 | 触发对象 | 说明 |
---|---|---|
1. 全局前置守卫 beforeEach(to, from, next) | this.$router | 导航钩子全局路由级级别 |
2. Home组件 路由独享守卫 beforeEnter(to, from, next) | this.$route | 导航钩子当前激活路由级别(进入) |
3. Home 组件 beforeRouteEnter(to, from, next) | Home 组件 | 导航钩子当前激活组件级别(进入) |
4. 全局解析守卫 beforeResolve(to, from, next) | this.$router | 导航钩子全局路由级级别 |
5. 全局后置钩子 afterEach(to, from) | this.$router | 导航钩子全局路由级级别 |
6. Home 组件 beforeCreate 生命周期 | Home 组件 | 组件生命周期 |
7. Home 组件 Created 生命周期 | Home 组件 | 组件生命周期 |
8. Home 组件 beforeMount 生命周期 | Home 组件 | 组件生命周期 |
9. Home 组件 mounted 生命周期 | Home 组件 | 组件生命周期 |
二 当从Home导航到About
导航钩子/组件生命周期 | 触发对象 | 说明 |
---|---|---|
1. Home 组件 beforeRouteLeave(to, from, next) | Home 组件 | 导航钩子当前失活路由级别(离开) |
2. 全局前置守卫 beforeEach(to, from, next) | this.$router | 导航钩子全局路由级级别 |
3. About 组件 路由独享守卫 beforeEnter(to, from, next) | this.$route | 导航钩子当前激活路由级别(进入) |
4. About 组件 beforeRouteEnter(to, from, next) | About 组件 | 导航钩子当前激活组件级别(进入) |
5. 全局解析守卫 beforeResolve(to, from, next) | this.$router | 导航钩子全局路由级级别 |
6. 全局后置钩子 afterEach(to, from) | this.$router | 导航钩子全局路由级级别 |
7. About 组件 beforeCreate 生命周期 | About 组件 | 组件生命周期 |
8. About 组件 Created 生命周期 | About 组件 | 组件生命周期 |
9. About 组件 beforeMount 生命周期 | About 组件 | 组件生命周期 |
10. Home 组件 beforeDestroy 生命周期 | Home 组件 | 组件生命周期 |
11. Home 组件 destroyed 生命周期 | Home 组件 | 组件生命周期 |
12. About 组件 mounted 生命周期 | About 组件 | 组件生命周期 |
总结规律:
整体执行规律,先执行的是导航守卫钩子,再执行组件自身的生命周期,完成全部的钩子函数。遇到组件切换的,则在新组件
beforeMount
后,mounted
前,旧组件发生beforeDestroy
和destroyed
如果有导航切换,则先触发的是失活组件的导航钩子
beforeRouteLeave(to, from, next)**
,再执行全局路由级别的前置导航钩子beforeEach(to, from, next)
,否则直接执行全局路由级别的前置钩子接着是执行被激活的路由对象级别的钩子
beforeEnter(to, from, next)
再是执行被激活的组件对象级别的钩子
beforeRouteEnter(to, from, next)
全局路由级别的
beforeResolve(to, from, next)
和afterEach(to, from)
最后是组件自身的生命周期
整理后的文档: https://chaihongjun.me/tools/vuehooks.html