vue2 生命周期详解

发布时间:2024-05-23 19:01

Title:vue2 生命周期详解

在探究vue生命周期之前,我们先提出一个问题:

new Vue()之后,发生了什么?,当数据(data)发生变化之后又发生了什么?

生命周期流程图

\"vue2

由上图可知,new Vue()之后,分别经过了以上几个阶段,分别是初始化阶段模板编译阶段挂载阶段更新阶段销毁阶段,那每一个阶段都干了些什么事呢?

初始化阶段

  1. 首先做一些初始化操作,主要是设置一些私有属性到vue实例中。
  2. 运行生命周期钩子函数beforeCreate
  3. 进入注入流程,处理属性,computedmethodsdataprovideinject,最后使用代理模式将这些属性挂载到实例中。
  4. 运行生命周期钩子函数created

编译阶段

  1. 生成render函数:如果有配置,直接使用配置的render函数,如果没有,使用运行时编译器,把模板编译成render函数。

挂载阶段

  1. 运行生命周期钩子函数beforeMount
  2. 创建一个Watcher,传入一个函数updeteCompontent,该函数会运行render,函数,并把render函数的返回结果vnode作为参数给_updete函数执行。

    // 伪代码
    updateCompontent(){
      _update(_render())
    }
    
    new Watcher(updateCompontent)

在执行render函数的过程中会搜集所有依赖,将来依赖发生变换时会出现执行updateCompontent函数。

在执行_update的过程中,会触发patch函数,由于目前还没有就的虚拟DOM树,因此直接为当前的虚拟DOM树的每一个节点生成对应elm属性,即真实DOM。

如果遇到创建一个组件实例的vnode,则会进入组件实例化流程,该流程同vue实例流程,同上初始化阶段,编译阶段,挂载阶段。最终会把创建好的组件实例挂载到vnodecompontentInstance属性中,以便复用。

  1. 运行生命周期钩子函数mounted

更新阶段

  1. 数据发生变化后,所有依赖该数据的watcher都会重新运行。
  2. watcher会被调度器Scheduler放到nextTick中运行,参考vue数据响应式原理,也就是微队列中,这样避免避免多个依赖的数据同时改变后被多次执行。
  3. 运行生命周期钩子函数beforeUpdate
  4. updateCompontent函数重新执行:

    // 伪代码
    updateCompontent(){
      _update(_render())
    }
    
    new Watcher(updateCompontent)

    在执行render函数的过程中,会先去掉之前的依赖,重新收集新的依赖,将来依赖发生变化时出现运行updateCompontent函数。

    在执行update函数的过程中,会触发patch函数,对比新旧两棵DOM树:

    当对比两棵DOM树的节点的时候,有两种情况,分别:

    • 普通html节点

      普通html节点的对比会导致真实节点被创建,删除,移动,更新

    • 组件节点

      组件节点的对比会导致组件被创建,删除,移动,更新。

      a)组件节点创建的时,进入组件实例化流程,同上初始化阶段,编译阶段,挂载阶段

      b)当旧组件节点删除时,会调用旧组件的$destroy方法删除组件,该方法会触发生命周期钩子函数beforeDestroy,然后递归调用组件的$destroy方法,然后出发生命周期钩子函数destroyed

      c)当组件更新时,相当于组件的updateCompontent函数被重新触发,进入渲染流程,同更新阶段

  1. 运行生命周期钩子函数updated

销毁阶段

  1. 当组件销毁的时候,会调用组件的$destroy方法删除组件,该方法会调用beforeDestroydestroyed方法
Vue.prototype.$destroy = function () {
  // 该属性标志着当前实例是否处于正在被销毁的状态
  if (vm._isBeingDestroyed) {
    return
  }
  callHook(vm, \'beforeDestroy\')
  vm._isBeingDestroyed = true
  // remove self from parent
  const parent = vm.$parent
  if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
    remove(parent.$children, vm)
  }
  // ...
  callHook(vm, \'destroyed\')
  // ...
  vm.$off()
}
  1. 执行beforeDestroy方法后,将当前组件实例从父组件实例的$children中删除

    if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
        remove(parent.$children, vm)
      }
  1. 移除自身的依赖监听和事件监听,实例内响应式数据的引用

    // teardown watchers
    if (vm._watcher) {
      vm._watcher.teardown()
    }
    let i = vm._watchers.length
    while (i--) {
      vm._watchers[i].teardown()
    }
    
    if (vm._data.__ob__) {
      vm._data.__ob__.vmCount--
    }
    vm._isDestroyed = true
    vm.__patch__(vm._vnode, null)
  1. 执行destroyed方法后,通过vm.$off()方法移除实例上的所有事件监听器,

扩展

回到开头那个问题,new Vue()之后,发生了什么?,当数据(data)发生变化之后又发生了什么?销毁呢?

\"vue2

// main.js

import Vue from \"vue\";
import App from \"./App.vue\";

Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App),
  beforeCreate() {
    console.log(\"vue实例 beforeCreate\");
  },
  created() {
    console.log(\"vue实例 created\");
  },
  beforeMount() {
    console.log(\"vue实例 beforeMount\");
  },
  mounted() {
    console.log(\"vue实例 mounted\", this);
  },
  beforeUpdate() {
    console.log(\"vue实例 beforeUpdate\");
  },
  updated() {
    console.log(\"vue实例 updated\");
  },
  beforeDestroy() {
    console.log(\"vue实例 beforeDestroy\");
  },
  destroyed() {
    console.log(\"vue实例 destroyed\");
  },
}).$mount(\"#app\");
// App



// A





// B





new Vue()后,会递归创建vue实例和组件实例:初始化阶段模板编译阶段挂载阶段

当所有子组件实例创建完成后vue实例才创建完成

vue实例 beforeCreate
vue实例 created
vue实例 beforeMount

App beforeCreate
App created
App beforeMount
    A beforeCreate
    A created
    A beforeMount
        B beforeCreate
        B created
        B beforeMount
        B mounted
    A mounted
App mounted

vue实例 mounted

\"vue2

当数据变化时

App beforeUpdate

A beforeUpdate
    B beforeUpdate
    B updated
A updated

App updated

\"vue2

当组件A,B销毁时

App beforeUpdate

A beforeDestroy
    B beforeDestroy
    B destroyed
A destroyed

App updated

\"vue2

以上仅个人理解,如有不当之处还请不吝赐教

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号