- 本文基于v2.5.1版本
- 开启源码调试:将
build/config.js文件中的genConfig函数内的config.sourceMap改为true
package.json文件中,通过script的dev命令,可以找到,源码构建命令入口文件:build/config.js,TARGET:web-full-dev,找到该文件,可以找到vue源码入口
src/platform/web/entry-runtime-with-compiler.js,
import Vue from './runtime/index'
src/platforms/web/runtime/index.js
import Vue from 'core/index'
src/core/index.js 找到vue核心代码入口
// vue的核心方法
import Vue from './instance/index'
// 初始化了一些全局的API
import { initGlobalAPI } from './global-api/index'
// 判断是否是ssr,返回boolean类型
import { isServerRendering } from 'core/util/env'
// 初始化全局api
initGlobalAPI(Vue)
// 为Vue的原型定义$isServer属性
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
// 为Vue的原型定义$ssrContext属性
Object.defineProperty(Vue.prototype, '$ssrContext', {
get () {
/* istanbul ignore next */
return this.$vnode && this.$vnode.ssrContext
}
})
Vue.version = '__VERSION__'
export default Vue
这个文件中,引入了Vue的核心方法,并通过initGlobalAPI,初始化了Vue的一些全局API。
export function initGlobalAPI (Vue: GlobalAPI) {
...
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
// 定义Vue.options.directives, Vue.options.filters, Vue.options.components
Vue.options = Object.create(null)
ASSET_TYPES.forEach(type => {
Vue.options[type + 's'] = Object.create(null)
})
...
// 为Vue.options.components添加KeepAlive
extend(Vue.options.components, builtInComponents)
// 定义Vue.use
initUse(Vue)
// 定义Vue.mixin
initMixin(Vue)
// 定义Vue.extend
initExtend(Vue)
// 定义Vue.component,Vue.directive,Vue.filter
initAssetRegisters(Vue)
}
src/core/instance/index.js
...
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')
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
...
看一个简单的例子:
<div id="app"></div>
new Vue({
el: '#app',
template: '<div>{{message}}</div>',
components: {
},
data: () => {
return {
message: 'Hello World',
}
},
created() {
}
})
当调用new Vue的时候,会调用this._init(options)方法,下面看一下_init方法:
src/core/instance/init.js
export function initMixin (Vue: Class<Component>) {
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
// 表明uid,可能有多个vue实例
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
// 如果是Vue的实例,则不需要被observe
vm._isVue = true
// merge options
// options参数的处理
if (options && options._isComponent) { // _isComponent 标识当前为 内部Component
// 内部Component 的 options 初始化
initInternalComponent(vm, options)
} else {
// 非内部Component的 options 初始化
const ctorOption = resolveConstructorOptions(vm.constructor)
vm.$options = mergeOptions(
ctorOption,
options || {},
vm
)
}
// 在render中将this指向vm._renderProxy
if (process.env.NODE_ENV !== 'production') {
initProxy(vm)
} else {
vm._renderProxy = vm
}
vm._self = vm
initLifecycle(vm) // vm的生命周期相关变量初始化
initEvents(vm) // vm的事件监听初始化
initRender(vm) // 初始化渲染函数
callHook(vm, 'beforeCreate') // 回调 beforeCreate 钩子函数
initInjections(vm) // resolve injections before data/props
// vm的状态初始化,prop/data/computed/method/watch都在这里完成初始化,因此也是Vue实例create的关键。
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, 'created') // 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)
}
// render & mount
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
}