vue生命周期

对照一个简单的例子,来看初始化的时候都发生了什么事。

<div id="app">
  <p>{{message}}</p>
</div>
<script type="text/javascript">
  var vm = new Vue({
    el: '#app',
    data: {
      message: '第一个vue实例'
    }
  })
</script>

先从构造函数看起,构造函数在src/core/instance/index.js

function Vue (options) { //Vue构造函数
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue)
  ) {
    warn('Vue is a constructor and should be called with the `new` keyword')
  }
  this._init(options)
}
//构造函数里判断如果不是生产环境并且没有使用new关键字的话,就打印一个警告
//然后执行_init()方法

可以看到最后执行了_init()方法,_init()方法在src/core/instance/init.js

Vue.prototype._init

export function initMixin (Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this
    //将新实例存在vm里
    // a uid
    vm._uid = uid++
    //为vm添加一个_uid属性

    let startTag, endTag
    //开始标记和结束标记,用于计算性能
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      startTag = `vue-perf-start:${vm._uid}`
      endTag = `vue-perf-end:${vm._uid}`
      //开始标记和结束标记用模板字符串生成,以vm._uid为基础来加以区别
      mark(startTag)
      //使用src/core/util/perf.js里定义好的mark方法创建开始标记
      //mark方法用于创建性能标记
    }

    // a flag to avoid this being observed
    vm._isVue = true
    //_isVue标记用于避免vm被监听
    // merge options
    console.log(options,1)
    console.log('\n\n\n\n\n\n')
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options)
      //内部组件初始化
    } else {
      console.log(2)
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
      //mergeOptions用于按照策略合并option
      //将合并好的option存为vm的属性$options
      //resolveConstructorOptions方法的参数是vm.constructor,其实就是Vue构造函数本身
      //这里就是将Vue构造函数上的options和用户传进来的options合并然后存成实例vm的$options属性
    }
    console.log(vm.$options,3)
    console.log('\n\n\n\n\n\n')
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm)
    } else {
      vm._renderProxy = vm
    }
    //如果是开发环境,vm._renderProxy就是一个proxy对象;生产环境vm._renderProxy就是实例自身
    // expose real self
    vm._self = vm
    //_self就是实例自身
    initLifecycle(vm)
    //initLifecycle,给vm实例添加一些生命周期标识,添加$parent,$root,$children,$refs,属性
    initEvents(vm)
    //initEvents,初始化事件相关属性
    initRender(vm)
    //initRender(vm),给实例添加虚拟dom相关属性
    callHook(vm, 'beforeCreate')
    //调用生命周期beforeCreate
    initInjections(vm) // resolve injections before data/props
    //在data和props初始化前处理注入的依赖
    initState(vm)
    //初始化关于数据的属性,props,methods,data,computed,watch
    initProvide(vm) // resolve provide after data/props
    //在data和props初始化之后处理提供依赖
    callHook(vm, 'created')
    //调用生命周期created

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      vm._name = formatComponentName(vm, false)
      //给实例添加一个_name属性<Anonymous>
      mark(endTag)
      //mark创建结束标记
      measure(`vue ${vm._name} init`, startTag, endTag)
      //计算初始化的时间
    }

    if (vm.$options.el) {
      vm.$mount(vm.$options.el)
    }//如果实例的options里有el参数,就去挂载vue到DOM元素上
  }
}

这其中vm.$options是实例上的初始化选项,它是由用户传入的options和Vue构造函数上的options合并而成,使用mergeOptions这个方法合并。

如果打印一下合并之前和合并之后的options就可以看到合并之后多添加了什么属性:

    console.log(options,1)
    if (options && options._isComponent) {
      initInternalComponent(vm, options)
    } else {
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      )
    }
    console.log(vm.$options,3)

合并之前的options就是用户传入的:

{
    data: {message: "hello world"},
    el: "#app"
}

合并之后增加了很多属性:

{
    data: mergedInstanceDataFn(),
    el: "#app",
    components: {
        __proto__: {
            KeepAlive:{...},
            Transition: {...},
            TransitionGroup: {...},
        }
    },
    directives: {
        __proto__: {
            model: {...},
            show: {...}
        }
    },
    filters: {},
    render: anonymous(),
    _base: Vue,
    staticRenderFns: []
}

 

posted @ 2018-04-03 21:09  hahazexia  阅读(281)  评论(0)    收藏  举报