Vue2 钩子函数

前言

本文将介绍 Vue2 中的钩子函数,重点是钩子函数的执行顺序(对于父子组件)以及合并原理(对于 mixin)。

钩子函数

首先来看看 Vue2 中组件钩子函数都有哪些:

  1. beforeCreate(组件创建之前)
  2. created(组件创建完成)
  3. beforeMount(组件挂载之前)
  4. mounted(组件挂载完成)
  5. beforeUpdate(组件更新之前)
  6. updated(组件更新完成)
  7. beforeDestroy(组件销毁之前)
  8. destroyed(组件销毁完成)

为了完整地演示上面的8个钩子函数的触发时机,我们把实现代码都放在一块,不过我们大致可以把这8个组件分为本部分,第一部分是组件从创建到显示会自动触发的钩子函数(前四个),第二部分是需要手动触发的钩子函数(后四个)。对于手动触发的我们分为两种,一种是点击按钮修改数据(触发beforeUpdate、update)、一种是跳转路由(触发beforeDestroyed、destroyed)。

beforeUpdate、updated 这两个钩子函数只有在组件生命周期内,数据有变化时才会被触发。最后两个钩子函数则是在组件被销毁时触发(比如:路由跳转、v-if 为 false)

单个组件加载

vue html 模板

<div class="container">
   <p>{{message}}</p>
   <button @click="change" class="btn btn-primary">改变数据</button>
   <router-link to="/home" class="btn btn-primary">跳转</router-link>
</div>

vue script 代码

<script>
export default {
  name: "Demo",
  data() {
    return {
      message: "云库网"
    };
  },
  methods: {
    change() {
      this.message = "http://yunkus.com";
    }
  },
  // 第一部分(组件创建时自动触发)
  beforeCreate() {
    console.log("%c======== beforeCreated ========", "color:red");
    console.log(this.$el);      // undefined
    console.log(this.$data);    // undefined
    console.log(this.message);  // undefined
  },
  created() {
    console.log("%c======== created ========", "color:red");
    console.log(this.$el);      // undefined
    console.log(this.$data);    // {...},已经可以获取
    console.log(this.message);  // 云库网
  },
  beforeMount() {
    console.log("%c======== beforeMount ========", "color:red");
    console.log(this.$el);      // undefined
    console.log(this.$data);    // {...}
    console.log(this.message);  // 云库网
  },
  mounted() {
    console.log("%c======== mounted ========", "color:red");
    console.log(this.$el);     // <div class="container">...</div>
    console.log(this.$data);   // {...}
    console.log(this.message); // 云库网
  },
  // 第二部分,手动触发
  beforeUpdate() {
    console.log("%c======== beforeUpdate ========", "color:red");
  },
  updated() {
    console.log("%c======== updated ========", "color:red");
  },
  beforeDestroy() {
    console.log("%c======== beforeDestroy ========", "color:red");
    console.log(this.$el);
    console.log(this.$data);
    console.log(this.message);
  },
  destroyed() {
    console.log("%c======== destroyed ========", "color:red");
    console.log(this.$el);
    console.log(this.$data);
    console.log(this.message);
  }
};
</script>

如果单纯的一个组件上面的顺序就是一个组件在生命周期内钩子函数触发顺序了。

首先,当组件创建并在页面中呈现后,自动地触发了 beforeCreate、created、beforeMount、mounted,在这四个钩子函数中我们也分别打印出了三个属性,可以发现不同的时机,属性值有可能不一样,一这点特别需要我们注意。

beforeCreated 钩子函数三个属性都全不到,而之后的created 和 beforeMount 拿不到当前实例的 $el 外,其它钩子函数(包括 destroyed )都能拿到三个属性的值。

两个组件之间跳转(A 跳转到 B)

下面就是路由跳转的情况,也就是从一个页面跳到另一个页面。对于两个组件之间的跳转,还可以细分

  • 页面 A 和 页面 B 中都没有引入子组件
  • 页面 A 中引入了子组件,页面 B 中没有引入子组件
  • 页面 A 中没有引入了子组件,页面 B 中引入了子组件
  • 页面 A 和 页面 B 中都引入了子组件

情况1:

  1. 页面 B 中的 beforeCreated、created、beforeMount 先触发
  2. 页面 A 中的 beforeDestroyed、destroyed 触发,然后再到 页面 B 中的 mounted 触发

情况2:

  1. 页面 B 中的 beforeCreated、created、beforeMount 依次触发
  2. 页面 A 中的 beforeDestroy
  3. 页面 A 中的子组件 beforeDestroy、destroyed
  4. 页面 A 中的 destroyed
  5. 页面 B 中的 mounted

情况3:

  1. 页面 B 中的 beforeCreated、created、beforeMount 依次触发
  2. 页面 B 中的子组件 beforeCreated、created、beforeMount 依次触发
  3. 页面 A 中的 beforeDestroy、destroyed 触发
  4. 页面 B 中的子组件 mounted 触发
  5. 页面 B 中的 mounted 触发

情况4:

  1. 页面 B 中的 beforeCreated、created、beforeMount 依次触发
  2. 页面 B 中的子组件 beforeCreated、created、beforeMount 依次触发
  3. 页面 A 中的 beforeDestroy 触发
  4. 页面 A 中的子组件 beforeDestroy 触发
  5. 页面 A 中的子组件 destroyed 触发
  6. 页面 A 中的 destroyed 触发
  7. 页面 B 中的子组件 mounted 触发
  8. 页面 B 中的 mounted 触发

除了上面这些情况外,还有一种情况也比较常见,vue 中的 mixin。

对于这种情况,官方也作一些基本的说明:

  1. 同名钩子函数将混合为一个数组,因此都将被调用。另外,混入对象的钩子将在组件自身钩子之前调用
  2. 数据对象在内部会进行递归合并,在和组件的数据发生冲突时以组件数据优先
  3. 值为对象的选项,例如 methods, components 和 directives,将被混合为同一个对象。两个对象键名冲突时,取组件对象的键值对

上面这些也需要我们牢记的,因为在用到 mixin 时你就会觉得上面这些三条说明很管用了。