vue2生命周期

113 阅读2分钟

前言
vue2 采用 monorepo 单体仓库管理模式管理项目代码;vue2 重点源码路径 vue/src/core/instance/index.ts

从 new Vue()实例化开始

Vue 初始化主要就干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。

function Vue(options) {
  if (__DEV__ && !(this instanceof Vue)) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}

# init方法 #
 Vue.prototype._init = function (options?: Record<string, any>) {
    const vm: Component = this
    vm._uid = uid++
    vm._isVue = true
    // 实例响应不通知观察
    vm.__v_skip = true
    // effect scope
    vm._scope = new EffectScope(true /* detached */)
    vm._scope._vm = true
    // merge options合并配置
    if (options && options._isComponent) {
      // 只是做了简单一层对象赋值,并不涉及到递归、合并策略等复杂逻辑。因此要比mergeOptions快
      initInternalComponent(vm, options as any)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor as any),
        options || {},
        vm
      )
    }
    /* 给实例添加代理监听;添加获取vm上面的属性、值 return target[key] */
    if (__DEV__) { // process.env.NODE_ENV !== 'production'
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    vm._self = vm
    initLifecycle(vm)
    initEvents(vm)
    initRender(vm)
    callHook(vm, 'beforeCreate', undefined, false)
    initInjections(vm) // resolve injections before data/props
    initState(vm)
    initProvide(vm) // resolve provide after data/props
    callHook(vm, 'created')

    if (vm.$options.el) { // 挂载一个未挂载的实例到元素上
      vm.$mount(vm.$options.el)
    }
  }

1.给实例 vm 添加一些基础属性配置、记录标识;合并 options 配置项:
(1).resolveConstructorOptions:简单返回

  Vue.options = Object.create(null)
  ASSET_TYPES.forEach(type => {
    Vue.options[type + 's'] = Object.create(null)
  })
Vue.options.components = {}
Vue.options.directives = {}
Vue.options.filters = {}
Vue.options._base = Vue

(2).根据不同的合并策略合并:props、inject、directives、(合并子选项是原始的对象时合并 extends、mixins)、合并其它属性

  • 初始化生命周期:赋值parentparent、root;给实例初始化一些属性(childrenchildren、refs、_provided、_watcher、_inactive、_directInactive、_isMounted、_isDestroyed、_isBeingDestroyed )
  • 初始化事件中心: vm._events = Object.create(null)
  • 初始化渲染:创建slotsslots、scopedSlots;以及渲染函数_c、$createElement=>vnode(虚拟的 node 节点)
  1. beforeCreate
  • v2 的 inject、Provide 非响应式;v3 的 inject、Provide 根据传入类型可响应,可非响应 *
  • initInjections:初始化注入数据;toggleObserving 关闭响应,通过 defineReactive 代理到实例访问;toggleObserving 开启响应
  • initState:初始化 props、methods、data、computed、watcher
  • initProvide:初始化该组件的下级注入数据
  1. created
  • $mount:执行_update=>patch 转成真正的 dom
渲染过程:
1. html字符串 → render函数 → vnode → 真实dom节点
2.  render函数 → vnode → 真实dom节点
src/core/instance/lifecycle.js
export function mountComponent (
  vm: Component,
  el: ?Element,
  hydrating?: boolean
): Component {
  vm.$el = el
  // ...
  callHook(vm, 'beforeMount')

  let updateComponent
  /* istanbul ignore if */
  if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
    updateComponent = () => {
      const name = vm._name
      const id = vm._uid
      const startTag = `vue-perf-start:${id}`
      const endTag = `vue-perf-end:${id}`

      mark(startTag)
      const vnode = vm._render()
      mark(endTag)
      measure(`vue ${name} render`, startTag, endTag)

      mark(startTag)
      vm._update(vnode, hydrating)
      mark(endTag)
      measure(`vue ${name} patch`, startTag, endTag)
    }
  } else {
    updateComponent = () => {
      vm._update(vm._render(), hydrating)
    }
  }


  new Watcher(vm, updateComponent, noop, {
    before () {
      if (vm._isMounted) {
        callHook(vm, 'beforeUpdate')
      }
    }
  }, true /* isRenderWatcher */)
  hydrating = false
  if (vm.$vnode == null) {
    vm._isMounted = true
    callHook(vm, 'mounted')
  }
  return vm
}
  1. beforeMount:dom 挂载之前
  2. 执行渲染函数
  3. mounted:在 dom 渲染完成之后
  4. beforeUpdate:当数据更新之后才会执行【new Watcher()中】
  5. updated:【在发布消息时触发】
  6. beforeDestroy:在组件销毁之前,此时 data、methods 可以用,释放内存
  7. destroyed 以及 activated & deactivated