Vue生命周期走向

166 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第3天,点击查看活动详情

生命周期

关于vue面试,多多少少都会说到生命周期,为了防止”刁难“,先给自己下一个狠药,把子、父、mixins、extends都混在一起,来看看生命周期的顺序

全局mixin、页面mixin.mixin、页面mixin、页面extends、子组件组成如下结构

// 假设每个mixin、组件和extends都有整个生命周期
Vue.mixin(全局mixin)
new Vue({
    mixins: [页面mixin] // 页面mixin里面还有个mixin,即是页面mixin.mixin
    extends: 页面extends,
    components: {valueDiv}
}}

图1是挂载流程,图2是销毁流程,我特意为其加上了不同颜色

  • 全局mixin:蓝色
  • 页面extends:灰色
  • 页面mixin.mixin:橙色
  • 页面mixin:绿色
  • 页面:黑色
  • 子组件:红色

image.png

image.png 仔细看图可以发现,其中全局mixin会随着page和组件valueDiv再度触发,因为全局mixin会作用到每个vue上,所以会重复触发。并且从中可以发现一定的顺序:

  • mixin的生命周期:全局->mixin.mixin->mixin->page
  • extends: extends->page
  • 每次父组件挂载前都会先挂载完子组件,销毁同理

总结

就生命周期而言可以通俗点说:权重低,先执行,按extends->mixins->page顺序触发。而实际上vue也是自顶而上,把mixin、extends这些分别合并成一个数组,再由指定的option函数处理。在触发的时候,因为会先从左到右调用生命周期函数,所以出现上图的生命周期顺序

而方法则是就近原则,例如:当前vue实例的methods里面的方法会覆盖同名方法

具体代码

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
  <script>
    function getLifeCycle (name, color) {
      const lifeCycle = ['beforeCreate', 'created', 'beforeMount', 'mounted', 'beforeDestroy', 'destroyed']
      const obj = {}
      lifeCycle.forEach(key => {
        obj[key] = function () {
          const fn = new Function(`console.log('%c ${this.$options.name ? this.$options.name + '-' : ''}${name}${key}', 'color:${color}')`)
          fn()
        }
      })
      return obj
    }
    Vue.mixin(getLifeCycle('全局', '#409EFF'))
    const vue = new Vue({
      name: '页面',
      el: '#app',
      mixins: [{
        ...getLifeCycle('mixin', '#67C23A'),
        mixins: [getLifeCycle('mixin.mixin', '#E6A23C')]
      }],
      extends: getLifeCycle('extends', '#909399'),
      template: `
        <main>
          <valueDiv></valueDiv>
          <button @click="destroy">消毁</button>
        </main>
      `,
      components: {
        valueDiv: {
          name: 'valueDiv',
          template: `<div>子组件</div>`,
          ...getLifeCycle('component', '#F56C6C')
        }
      },
      methods: {
        destroy () {
          this.$destroy()
        }
      },
      ...getLifeCycle('page', '#303133')
    })
  </script>
</body>
</html>