vue的生命周期(包括路由周期)

512 阅读6分钟

参考链接:juejin.cn/post/684490… image

1、触发钩子的完整顺序

将路由导航、keep-alive、和组件生命周期钩子结合起来的,触发顺序,假设是从a组件离开,第一次进入b组件:

  1. beforeRouteLeave:路由组件的组件离开路由前钩子,可取消路由离开。
  2. beforeEach: 路由全局前置守卫,可用于登录验证、全局路由loading等
  3. beforeEnter: 路由独享守卫。为某些路由单独配置守卫。
  4. beforeRouteEnter: 路由组件的组件进入路由前钩子。在路由独享守卫后调用 不!能!获取组件实例 this,组件实例还没被创建
  5. beforeResolve:路由全局解析守卫
  6. afterEach:路由全局后置钩子 vue原本的生命周期钩子函数:
  7. beforeCreate:组件生命周期,不能访问this。
  8. created:组件生命周期,可以访问this,不能访问dom。
  9. beforeMount:组件生命周期
  10. deactivated: 离开缓存组件a,或者触发a的beforeDestroy和destroyed组件销毁钩子。
  11. mounted:访问/操作dom。
  12. activated:进入缓存组件,进入a的嵌套子组件(如果有的话)。
  13. 执行beforeRouteEnter回调函数next。

2、单一组件钩子执行顺序

  1. beforeCreate
  2. created
  3. beforeMount
  4. mounted
  5. beforeUpdate
  6. updated
  7. activated
  8. deactivated
  9. beforeDestroy
  10. destroyed
  11. errorCaptured

3、dom访问情况

beforeCreate 和 created:在这两个生命周期中,Vue 实例被创建出来,但还没有生成真正的 DOM 对象,因此无法访问任何 DOM 对象。

beforeMount 和 mounted:在 beforeMount 钩子函数中,仍然无法访问到真正的 DOM 对象;而在 mounted 钩子函数中,真正的 DOM 对象已经生成,可以进行访问。

beforeUpdate 和 updated:在这两个生命周期中,DOM 已经生成,可以进行访问。但是需要注意的是,在更新数据时,DOM 也可能会被重新渲染,因此在更新 DOM 前后,要先进行必要的操作,避免出现意外的结果。

beforeDestroy 和 destroyed:在 beforeDestroy 钩子函数中,Vue 实例还没有被销毁,依然可以访问 DOM 对象;而在 destroyed 钩子函数中,Vue 实例已经被彻底销毁,无法再访问 DOM 对象。

4、vue-router导航守卫过程

(1)、全局守卫

vue-router全局有三个守卫:

  • router.beforeEach 全局前置守卫 进入路由之前
  • router.beforeResolve 全局解析守卫(2.5.0+) 在beforeRouteEnter调用之后调用
  • router.afterEach 全局后置钩子 进入路由之后

(2)、路由组件内的守卫

  • beforeRouteEnter 进入路由前
  • beforeRouteUpdate (2.2) 路由复用同一个组件时
  • beforeRouteLeave 离开当前路由时

完整的路由导航解析流程(不包括其他生命周期):

  • 触发进入其他路由。
  • 调用要离开路由的组件守卫beforeRouteLeave
  • 调用局前置守卫:beforeEach
  • 在重用的组件里调用 beforeRouteUpdate
  • 调用路由独享守卫 beforeEnter。
  • 解析异步路由组件。
  • 在将要进入的路由组件中调用beforeRouteEnter
  • 调用全局解析守卫 beforeResolve
  • 导航被确认。
  • 调用全局后置钩子的 afterEach 钩子。
  • 触发DOM更新(mounted)。
  • 执行beforeRouteEnter 守卫中传给 next 的回调函数

5、父子组件生命周期执行顺序

这个顺序的原因是 1、Vue.js 的设计需要确保父组件在子组件之前创建和更新,以便子组件拿到父组件传递数据和属性。 2、当组件挂载到 DOM(或销毁)时,子组件需要先挂载(或销毁),以确保 DOM 结构的正确性。 总之,这个顺序是 Vue.js 的生命周期钩子函数设计的结果,以确保父子组件之间的正确数据传递和 DOM 结构。

(1)加载渲染过程

父组件先创建,然后子组件创建;子组件先挂载,然后父组件挂载。 3 4 1

父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount->子mounted->父mounted

子组件挂载完成后,父组件还未挂载。所以组件数据回显的时候,在父组件mounted中获取api的数据,子组件的mounted是拿不到的。 解决办法: (1)在父组件传递接口的数据给子组件时,一定要在子组件标签上加上v-if="传递的接口数据" (2)在子组件中 watch 监听,父组件获取到值,这个值就会变化,自然是可以监听到的

watch:{
    data:{
      deep:true,
      handler:function(newVal,oldVal) {
        this.$nextTick(() => {
          this.data = newVal
          this.data = newVal.url ? newVal.url : ''
        })
      }
    },
}

从父组件点击调用接口并显示子组件,子组件拿到数据并监听在watch中调用方法并显示

(2)更新过程

父组件先开始更新,子组件再开始,子组件先完成更新 1 2 1

父beforeUpdate->子beforeUpdate->子updated->父updated

(3)销毁过程

父组件先开始销毁,子组件再开始,子组件先完成销毁 1 2 1

父beforeDestroy->子beforeDestroy->子destroyed->父destroyed

6、keep-alive activated生命周期

keep-alive缓存组件,刷新的时候保持状态 避免组件内的数据重复渲染,直接可以在页面中调用。

优点:组件切换过程过,组件被保存在内存中,防止重复渲染,减少加载时间,提高性能。

坑:如果遇到二级路由访问页面。想保留上一次的url 在beforeRouteLeave时记录当前的路由。(不能在deactivated周期中加,加的路由会是跳转后的路由) 这样从其他地方点回来的时候就可以进入该二级路由中。而不是进入该路由的一级路由中。 参考视频:www.bilibili.com/video/BV1EZ…

原理:

缓存的组件以 [key,vnode] 的形式记录,keys记录缓存的组件key,依据include、exclude的值,并且当超过设置的max根据LRU算法(Least Recently Used)最近最少使用,进行清除。

7、我们的请求放在哪个生命周期会更合适

一般来说,会有两种回答:created和mounted。 上文已经讲了,这两个回答,前者是数据已经准备好了,后者是连dom也已经加载完成了,那么到底哪个才是正确答案呢?

其实,两个都是可以的,但是mounted会更好。

  • 使用逻辑上,有的时候我们接到返回的数据的时候可能要在回调函数中去进行一些Dom的操作,可是created阶段我们还没有将真实Dom加载出来,所以相对而言我们还是在mounted去调用要好一些。
  • 如果是服务端渲染,我们将其放入created中进行,因为服务端不支持mounted。

8、vue3和vue2的区别

(1)主要针对beforeDestroy和Destoryed两个生命周期

beforeDestroy -> beforeUnmount

Destoryed -> Unmounted

(2)options API 和 composition API 在生命周期上也有一些小的不同: composition API 提供了 setup 函数作为入口函数,替换了 beforeCreate 和 created 这两个生命周期钩子。 所以在实际开发中,我们可以简单的把 setup 理解为 created 进行使用。