简述VUE组件初始化

版权声明:个人笔记,不喜勿喷 https://blog.csdn.net/qq_39571197/article/details/87599088

http://assets.processon.com/chart_image/5c7361a5e4b03334b528572a.png

首先改正了自己的一个想法,生命周期、生命周期钩子是两个不同的概念,不能混为一谈。 

其次,由于vue嵌套起来,就像树结构,所以经常看到这种代码

/* 就是从父级寻找数据,甚至父..父父级 */
parent.$root

1、Vue构造函数,一切都在_init()方法里;

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

2、生成组件ID,然后对options进行一些处理

var vm = this;
vm._uid = uid$3++;

 3、然后有一波优化组件的操作,initInternalComponent()方法(我会再研究的,明白了之后再更新)

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 {
    vm.$options = mergeOptions(
      resolveConstructorOptions(vm.constructor),
      options || {},
      vm
    );
}

/* 注意options._isComponent,反正你new Vue()的时候,是肯定不会执行的,什么时候执行呢? */
new Vue({
    el: '#app',
    components: {
      /* 比如这个子组件,_init()的时候,就会执行这里的代码了 */
      ChildComponent:{
          create(){
              console.log('child-create');  
          },
      },
    },
    data: {
        test: 1
    }
})

4、接下来的代码大致就是这样的

initLifecycle(vm);
initEvents(vm);
initRender(vm);
callHook(vm, 'beforeCreate');
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');

4.1、initLifecycle()

初始化生命周期,主要是相关的属性,(按我以前的理解,我还以为是触发钩子呢...)

/* 大致如下 */
vm.$parent = parent;
vm.$root = parent ? parent.$root : vm; 

vm.$children = [];
vm.$refs = {};

vm._watcher = null;
vm._inactive = null;
vm._directInactive = false;
vm._isMounted = false;
vm._isDestroyed = false;
vm._isBeingDestroyed = false;

4.2、initEvents()

核心:观察者模式,事件都会被添加到vm._events属性中

解析事件之后,通过$on()添加到vm._events,对于$once()的事件,执行完会调用$off()关闭事件。

使用到方法,updateComponentListeners()、updateListeners() 。

4.3、initRender()

初始化render相关的属性,$attrs、$listeners为响应式属性,其中_parentListeners是上面提到的initInternalComponent()方法生成的。

/* istanbul ignore else */
{
      defineReactive$$1(vm, '$attrs', parentData && parentData.attrs || emptyObject, function () {
        !isUpdatingChildComponent && warn("$attrs is readonly.", vm);
      }, true);
      defineReactive$$1(vm, '$listeners', options._parentListeners || emptyObject, function () {
        !isUpdatingChildComponent && warn("$listeners is readonly.", vm);
      }, true);
}

使用到方法,createElement()、defineReactive()。

4.4、 beforeCreate钩子

4.4、 initInjections()

这个是初始化 provide/inject 机制,父组件设置provide,子组件、子...子子组件都可以使用inject接收。

提示:provide 和 inject 绑定并不是可响应的。这是刻意为之的。然而,如果你传入了一个可监听的对象,那么其对象的属性还是可响应的,例子,https://blog.csdn.net/qq_39571197/article/details/87692484

使用到方法,resolveInject ()、defineReactive()。

4.5、initState()

#占

4.6、initProvide()

前面提到了,initInjections()在initProvide()之前。

这个函数很简单,就是执行以下,把数据挂载到this,不会调用defineReactive()使其变成响应式数据。

使用到方法,无。

5、接下来和开发与调试有关,查看性能

 if (config.performance && mark) {
        vm._name = formatComponentName(vm, false);
        mark(endTag);
        measure(("vue " + (vm._name) + " init"), startTag, endTag);
 }

这个需要搭配 Vue Performance Devtool  浏览器扩展使用。

6、最后一步,显示到页面

 if (vm.$options.el) {
        vm.$mount(vm.$options.el);
 }

$mount()是Vue.prototype上的一个方法;

6.1、对于new Vue()来说,如果不传入el属性,也可以从实例上手动调用$mount()方法

6.2、对于组件来说,在componentVNodeHooks中有个init()方法,会自动执行$mount()方法。

猜你喜欢

转载自blog.csdn.net/qq_39571197/article/details/87599088