与mixin相关的执行顺序

4,828 阅读2分钟

前几天看到有关vue全局mixin与组件的生命周期执行顺序以及父子组件生命周期执行顺序有关的一道综合型的题目:

main.js

import Vue from 'vue'
import App from './App.vue'

Vue.mixin({
  data() {
    console.log(`${this.$options.name}: data (from Mixin)`)
    return {
      name: 'Mixin2'
    }
  },
  beforeCreate() {
    console.log(`${this.name}: beforeCreate (from Mixin)`)
  },
  beforeMount() {
    console.log(`${this.name}: beforeMount (from Mixin)`)
  },
  mounted() {
    console.log(`${this.name}: mounted (from ${this.from()})`)
  },
  methods: {
    from() {
      return 'Mixin3'
    }
  }
})

Vue.config.productionTip = false

new Vue({
  name: 'Root1',
  data() {
    console.log('Root: data (from Root)')
    return {
      name: 'Root2'
    }
  },
  beforeCreate() {
    console.log('Root: beforeCreate (from Root)')
  },
  created() {
    console.log('Root: created (from Root)')
  },
  beforeMount() {
    console.log('Root: beforeMount (from Root)')
  },
  mounted() {
    console.log('Root: mounted (from Root)')
  },
  methods: {
    from() {
      return 'Root3'
    }
  },
  render: h => h(App)
}).$mount('#app')

App.vue

<template>
  <div id="app">
  </div>
</template>

<script>
export default {
  name: 'App1',
  data() {
    console.log('App: data (from App)')
    return {
      name: 'App2'
    }
  },
  beforeMount() {
    console.log('App: beforeMount (from App)')
  },
  mounted() {
    console.log('App: mounted (from App)')
  },
  methods: {
    from() {
      return 'App3'
    }
  },
  render: h => h('h1')
}
</script>

看起来像一堆‘console.log’的代码,仔细理清就很好处理了,这里将App挂载到了Root上,可以把他们看成是父子组件,这里需要判断父子组件的执行顺序;Vue.mixin全局混入,就要判断是mixin先执行还是组件先执行。 直接看结果吧:

1 undefined: beforeCreate (from Mixin)
2 Root: beforeCreate (from Root)
3 Root: data (from Root)
4 Root1: data (from Mixin)
5 Root: created (from Root)
6 Root2: beforeMount (from Mixin)
7 Root: beforeMount (from Root)
8 undefined: beforeCreate (from Mixin)
9 App: data (from App)
10 App1: data (from Mixin)
11 App2: beforeMount (from Mixin)
12 App: beforeMount (from App)
13 App2: mounted (from App3)
14 App: mounted (from App)
15 Root2: mounted (from Root3)
16 Root: mounted (from Root)

由此,可以总结出以下规律:

  1. 组件内data是在beforeCreatecreated之间执行(从2 -> 3 -> 5可以看出)

  2. 父子组件生命周期执行顺序:父组件创建完成后会等待子组件挂载完成才会挂载到页面上,所以父子组件生命周期执行顺序为:

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

  3. data执行组件先于mixin(从3 -> 4、9 -> 10可以看出)

数据对象在内部会进行递归合并,并在发生冲突时以组件数据优先。

  4. 生命周期执行mixin先于组件(1 -> 2、6 -> 7、11 -> 12可以看出)

同名钩子函数将合并为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用。

  5. 若组件和mixin的methods重名,则取组件的methods。(从13、14、15、16可以看出)

值为对象的选项,例如 methods、components 和 directives,将被合并为同一个对象。两个对象键名冲突时,取组件对象的键值对。