# 生命周期钩子

生命周期』指的是从组件被创建并添加到 DOM,到组件被销毁的整个过程。

Vue 的生命周期有 4 个阶段,每个阶段都有 2 个『钩子函数』,这一共就是 8 个。这 8 个函数也被称为生命周期钩子,它们在 4 个阶段中会被依次调用,有的甚至会被反复调用。

8 个生命周期钩子,其中 4 个是带有 before 前缀的钩子,它们会先于其它钩子被调用。

# 钩子
1 beforeCreate
2 created
3 beforeMount
4 mounted
5 beforeUpdate
6 updated
7 beforeDestroy
8 destroyed

尽管看起来确实很多钩子,但你只需要记住 4 个(created、mounted、updated 和 destroyed),然后可以推导出其它 4 个。

Vue 从页面初始化到页面完全渲染经历了什么?

# 1. new View()

在 beforeCreate 之前就干了一件事情,就是 new Vue()创。被创建出来的 vue 对象是一个逻辑上非完整实例对象,里面什么都没有,data 和 methods 都还没有初始化。

new 是一切的起点,new 之后才是『各个阶段』。

# 2. 创建阶段

创建阶段的『创建』很容易造成误会,误以为这是是创建 vue 对象,而实际上 vue 对象的创建时 new View() 干的时前。

在创建阶段,Vue 干的事情有 2 件:

  1. new Vue() 创建的 vue 实例的 data 和 methods 进行初始化。

  2. 根据 template 属性(或 render 函数)——在内存中——生成 DOM Element 对象。

所以,在创建阶段的『前半段』data 和 methods 是不可用的(undefined),与此相关的 computed 和 watch 也是不可用的。而在『后半段』它们就都是可用的了。

需要强调的是,创建阶段『创建』的是 DOM 的 Element 对象,而它们仅仅是被创建出来,还未挂载到页面的 DOM 树上,因此,创建阶段对页面显示效果的影响仍然为零。

最后,逻辑上,在这个阶段,你可以进行逻辑操作,但不应该进行 DOM 操作。

  • beforeCreate 被调用时,意味着此时是创建阶段前半段;

  • created 被调用时,意味着此时是创建阶段后半段。

# 3. 挂载阶段

挂在阶段的主要工作就是将创建阶段创建的 DOM Element 挂载到 HTML 页面的 DOM 树上,这样,这些 DOM Element 所代表的元素才能在页面上展现出来。

所以,在挂载阶段的『前半段』vue 实例的 $el 是不可用的,于此同时,页面上也是没有内容展示的;而挂载阶段的『后半段』,$el 就变成可用了,页面也会有你所期望的内容呈现出来。

另外,$refs$el 一样,在 mounted 之后才可用。

  • beforeMount 被调用时,意味着此时是挂载阶段前半段;

    所以此时我们通过 JS 的 innerText 获取页面元素的文本时内容为插值表达式本身(),而非具体的数据内容。

  • mounted 被调用时,意味着此时是挂载阶段后半段。

    另外,即便是挂载阶段后半段,Vue 2.0 也不保证挂在了当前组件的所有子组件,即,有可能你的组件的显示效果有残缺(有子组件未挂载、未渲染)。如果需要整个视图渲染完毕,可以使用 vm.$nextTick

    mounted: () => {
      this.$nextTick(() => { // 使用 nextTick 来等待所有的视图都渲染完毕
        // 执行代码
      });
    }
    

# 4. 更新阶段

和创建、挂载阶段不同,『更新阶段』会反复出现。因为,更新阶段是 Vue 促使 data 数据和页面显示重新一致的阶段。

即,Vue 发现 data 中的数据有更新(即,data 和页面数据不一致),它就会通过 DOM 操作区更新(重新渲染)页面,从而再次达到 data 数据和页面显示的一致。

显而易见,在这个阶段的『前半段』vue 实例的 data 和页面上的显示是不一致的;而在这个阶段的『后半段』它俩就再一次一致了。

  • beforeUpdate 被调用时,意味着此时是更新阶段前半段,这个时候,data 数据是最新的,但是页面数据是旧的;

  • updated 被调用时,意味着此时是更新阶段后半段,这个时候,页面数据已经更新成 data 那样了;

# 5. 销毁阶段

  • beforeDestroy:vue 实例销毁之前调用。在这一步,vue 实例仍完全可用。

  • destroyed:vue 实例销毁之后调用。调用后,vue 实例指示的所有东西都会解绑,所有的事件监听器会被移除,所有的子实例也会被销毁。

# 6. 补充:keep-alive

keep-alive 标签包裹的组件在它们第一次被创建的时候就被缓存下来。与此相关的有两个生命周期钩子函数:activated 和 deactivated。当组件在内被切换时,activated 和 deactivated 这两个生命周期钩子函数将会被对应执行。

activated:在组件被激活时调用,在组价第一次渲染时也会被调用,之后每次 keep-alive 激活时被调用。

deactivated:在组件被停用时调用。

注意:只有组件被 keep-alive 包裹时,这两个生命周期才会被调用,如果作为正常组件使用,是不会被调用的。

vue 钩子