vue2.x源码解析(二)

上个文章我们已经知道了vue的入口文件在哪里,这篇文章就先分析入口文件,来看看vue究竟是什么。
首先先来看这行代码:

import Vue from './runtime/index'

然后我们找到这个index文件,然后看这行:

import Vue from 'core/index'

这个index文件通过上一篇的讲解可以得出他的路径为==src/core/index ==,我们来看看这个文件:

import { initMixin } from './init'
import { stateMixin } from './state'
import { renderMixin } from './render'
import { eventsMixin } from './events'
import { lifecycleMixin } from './lifecycle'
import { warn } from '../util/index'

//vue定义
function Vue (options) {
  //判断是否通过new实现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)
}

//minin向vue原型中增加方法,并拆分到不同文件下
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)

export default Vue

到这里我们终于看到了Vue的定义,是用function实现的一个类,为什么要用幻术而不用class呢,我们可以在后面看到有许多Mixin函数,这些函数都是Vue的一些方法,是通过挂载到Vue的prototype上实现的,这样就不用在一个模块里将所有的都实现出来,而是可以去分散到多个模块,这就是用class难于实现的,这种技巧值得我们去学习。

数据驱动

我们通过vue可以使用简单的模板语法去将数据渲染成dom,举个例子:

//...
<div>{{message}}</div>
//...
data(){
  return {
    message:10
  }
}

这就是一个很简单的数据驱动,那么他究竟是如何实现的呢?
首先,还是要从入口代码分析,通过之前找到的代码我们可以了解到vue只能通过new来初始化,之后便会调用_init函数,我们来找找这个函数,因为我用的是vscode,所以直接在全局搜索里搜这个函数名就可以了,最后我们可以确认这个函数是在src/core/instance/init,js文件里,来看一下代码:

export function initMixin(Vue: Class<Component>) {
  Vue.prototype._init = function (options?: Object) {
    const vm: Component = this;
    // a uid
    vm._uid = 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}`;
      mark(startTag);
    }

    // a flag to avoid this being observed
    vm._isVue = true;
    // merge options
    //合并options,下面是判断是否为组件
    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 {
      //将Vue上的一些option扩展到vm.$options
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      );
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== "production") {
      initProxy(vm);
    } else {
      vm._renderProxy = vm;
    }
    // expose real self
    vm._self = vm;
    initLifecycle(vm);
    initEvents(vm);
    initRender(vm);
    callHook(vm, "beforeCreate");//生命周期
    initInjections(vm); // resolve injections before data/props
    initState(vm);//作用为初始化prop,data,methods,watch,computed等属性
    initProvide(vm); // resolve provide after data/props
    callHook(vm, "created");//生命周期

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== "production" && config.performance && mark) {
      vm._name = formatComponentName(vm, false);
      mark(endTag);
      measure(`vue ${vm._name} init`, startTag, endTag);
    }

    if (vm.$options.el) {
      //组件初始化不传el,所以是组件自己接管了$mount过程
      vm.$mount(vm.$options.el);
    }
  };
}

我们可以看到初始化时主要就是干了几件事情,合并配置,初始化生命周期,初始化事件中心,初始化渲染,初始化 data、props、computed、watcher 等等。
所以这篇文章就先说到这里,之后会接着分析vue是如何实现数据驱动并介绍vue实例是如何进行挂载的,之后会补链接,有错误欢迎留言斧正。

©️2020 CSDN 皮肤主题: 创作都市 设计师:CSDN官方博客 返回首页