vue的构造函数new Vue
一切都是从Vue的构造函数开始的...,当执行了npm run dev的构建过程就是执行这些初始化的过程,首先在node_modules中找到vue源码,core文件是对vue内核的包装,入口文件index.js,先从一个构造函数开始,然后在Vue的prototype上进行功能的拓展的。之后initGlobalAPI函数在Vue实例上进行属性的添加,最后拓展了vue原型上的isServer ssrContent FunctionalRenderContent,写入vue的version,返回vue实例。
// ./node_modules/src/core/instance/index.js
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) {
if (process.env.NODE_ENV !== 'production' &&
!(this instanceof Vue)
) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
// 调用new Vue()的时候_init() 将被执行
this._init(options)
}
// Vue的初始化都是操作Vue.prototype 设置它的属性
initMixin(Vue)
//在Vue的原型上添加_init函数 Vue.prototype._init = function (options?: Object) {//...}
stateMixin(Vue) //非生产环境下为props data设置set拦截;之后设置$set、$delete 以及 $watch方法
eventsMixin(Vue) // 添加原型上的监听方法
// Vue.prototype.$on = function (event: string | Array, fn: Function): Component {}
// Vue.prototype.$once = function (event: string, fn: Function): Component {}
// Vue.prototype.$off = function (event?: string | Array, fn?: Function): Component {}
// Vue.prototype.$emit = function (event: string): Component {}
lifecycleMixin(Vue)
//原型添加声明周期函数方法
// Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
// Vue.prototype.$forceUpdate = function () {}
// Vue.prototype.$destroy = function () {}
renderMixin(Vue) 为原型又添加了一系列的方法
// installRenderHelpers 函数中
/**Vue.prototype._o = markOnce
Vue.prototype._n = toNumber
Vue.prototype._s = toString
Vue.prototype._l = renderList
Vue.prototype._t = renderSlot
Vue.prototype._q = looseEqual
Vue.prototype._i = looseIndexOf
Vue.prototype._m = renderStatic
Vue.prototype._f = resolveFilter
Vue.prototype._k = checkKeyCodes
Vue.prototype._b = bindObjectProps
Vue.prototype._v = createTextVNode
Vue.prototype._e = createEmptyVNode
Vue.prototype._u = resolveScopedSlots
Vue.prototype._g = bindObjectListeners
Vue.prototype.$nextTick = function (fn: Function) {}
Vue.prototype._render = function (): VNode {}
**/
export default Vue
Vue添加全局API
// ./src/core/index.js
// 从 Vue 的出生文件导入 Vue
import Vue from './instance/index'
import { initGlobalAPI } from './global-api/index'
import { isServerRendering } from 'core/util/env'
import { FunctionalRenderContext } from 'core/vdom/create-functional-component'
// 将 Vue 构造函数作为参数,传递给 initGlobalAPI 方法,该方法来自 ./global-api/index.js 文件
initGlobalAPI(Vue)
/** options初始化
Vue.options = {
components: {
KeepAlive
},
directives: Object.create(null),
filters: Object.create(null),
_base: Vue
}
在Vue上添加了.use .mixin .extend ,component . directive .filter方法
**/
// 在 Vue.prototype 上添加 $isServer 属性,该属性代理了来自 core/util/env.js 文件的 isServerRendering 方法
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
// 在 Vue.prototype 上添加 $ssrContext 属性
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
// expose FunctionalRenderContext for ssr runtime helper installation
Object.defineProperty(Vue, 'FunctionalRenderContext', {
value: FunctionalRenderContext
})
// Vue.version 存储了当前 Vue 的版本号
Vue.version = '__VERSION__'
// 导出 Vue
export default Vue
平台兼容platform
在Vue.options 上添加web weex不同平台运行时的特定组件和指令。覆盖一些Vue.config属性添加平台,构建了不同的输出。每个不同形式的包又分为运行时版和完整版,完整版比运行时版多了compiler,这个文件的第一个影响是它重写了 Vue.prototype.$mount 方法;第二个影响是添加了 Vue.compile 全局API。
merge调用合并选项
// html
// js
var vm = new Vue({
el: '#app',
data: {
test: 1
}
})
调用构造函数_init时传入参数options,在init中声明了vm常量指向当前的vue实例,接下来就是对vm.$options上的选项进行合并,props inject directive属性的多种写法都会被规范化处理成对象的形式。因为 Vue 要对选项进行处理,这个时候好的做法就是,无论开发者使用哪一种写法,在内部都将其规范成同一种方式,这样在选项合并的时候就能够统一处理。
mergeOptions(Vue.options, options,vm){
//规范化处理
}
从instance/index 首先执行的initMixin(Vue) (instance/init)给Vue原型上定义了一个_init方法,过程:options处理-renderProxy-vm生命周期相关变量初始化-vm事件监听初始化-vm状态初始化-render&mount。
调用new Vue时传入options,mergeOptions(instance/global-api/extend)方法 解析构造函数的options,当为Vue混入一些options superOptions就会发生变化,跟之前存储的cachedSuperOptions不等,主要进行相关的sub.superOptions更新返回merge自己的options与父类的options属性
在merge时将更新的options更新到子类的superOptions,返回merge自己和父类的options,通过Vue提供的strats对象hook的方式区分公共处理和特殊处理,mergeOptions(instance/util/options) 只有在方法调用的时候进行merge,其他情况将进行处理。
1、mergeOptions对父子选项进行合并处理,实现Vue选项的规范化和选项合并,可以通过Vue.config.optionMergeStrategies来自定义合并策略
2、当通过vue.extend调用mergeOptions函数时拿不到第三个参数vm,这时就是在实例化子组件,不论是new Vue还是子组件的实例化,都会将数据处理成一个函数,避免了组件间数据互相影响;
3、由于props inject选项是在data之前进行初始化,所以为了保证我们能够使用props初始化data中的数据,data函数将会在初始化的时候进行合并处理。将生命周期函数合并成了数组的形式;
4、将指令,过滤器和组件合并,这时候在原形上添加了一些如KeepAlive、Transition、(抽象组件不会渲染成真实的组件)TransitionGroup,这就是内置组件,props inject methods computed都会被处理为一个纯对象。mixin extend也会被混入
5、通过proxy实现对vm的代理