上个文章我们已经知道了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实例是如何进行挂载的,之后会补链接,有错误欢迎留言斧正。