本菜鸡阅读源码看的是Vue2.6,问我为啥不看3?那我至少得先看懂2吧,我觉得2还是很经典的,虽然现在Vue3的组合式API尤大很推崇,但是我还是习惯在Vue3里写声明式的,真的是个人习惯吧(我一定慢慢改,主要是我现在没项目做啊!),性能上小项目应该是没多大影响。阅读源码一个是为了以后面试可以吹逼,还有就是向优秀代码学习,理解他的组织架构,最后可以给自己使用的时候排坑。
0.import Vue
说到new Vue() 首先你得有Vue,先上demo
import Vue form 'Vue'
new Vue()
这里分为两个过程,一个是构造函数引入(或者说是类的引入),第二个才是真正的创建了一个vue的实例。光引入Vue这个构造函数,其实这里已经做了大量工作了,主要是给Vue加一些静态属性和原型链上的属性,如果用ES6的class表示大概是下面这个样子
export class Vue {
constructor(options){
this._init(options)
}
// 静态属性和方法
static key
static foo1(){}
...
// 原型属性和方法
public key2
public foo2(){}
...
...
_init(){}
}
对于ES5来说基本上是这样的
// 原型属性
Vue.prototype.key =
// 静态属性
Vue.key2 =
// 构造函数
function Vue(options){
this._init(options)
}
1.Vue类的创建
1.1 Vue的入口
platforms/web/entry-runtime.js
import Vue from './runtime/index'
export default Vue
1.2 运行时文件
platform/web/runtime/index.js
Vue.config.mustUseProp = mustUseProp
Vue.config.isReservedTag = isReservedTag
Vue.config.isReservedAttr = isReservedAttr
Vue.config.getTagNamespace = getTagNamespace
Vue.config.isUnknownElement = isUnknownElement
// 注册内置指令 v-model v-show
extend(Vue.options.directives, platformDirectives)
// 驻车内置组件 Transition,TransitionGroup
extend(Vue.options.components, platformComponents)
Vue.prototype.__patch__ = inBrowser ? patch : noop
Vue.prototype.$mount = function(){}
1.3 内核文件
core/index.js
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(Vue)
// ssr相关,可先忽略
Object.defineProperty(Vue.prototype, '$isServer', {
get: isServerRendering
})
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 = '__VERSION__'
core/global-api/index.js中initGlobalAPI挂载里一些Vue类上的静态属性和方法
export function initGlobalAPI (Vue: GlobalAPI) {
Object.defineProperty(Vue, 'config', configDef)
Vue.util = {
warn,
extend,
mergeOptions,
defineReactive
}
Vue.set = set
Vue.delete = del
Vue.nextTick = nextTick
Vue.observable = <>(obj: T): T => {
observe(obj)
return obj
}
// ...
//前面挂载里了一些Vue的静态方法
// keep-alive组件
extend(Vue.options.components, builtInComponents)
// Vue.use
initUse(Vue)
// Vue.mixin
initMixin(Vue)
// Vue.extend
initExtend(Vue)
// Vue.components, Vue.directive, Vue.filter
initAssetRegisters(Vue)
}
1.4 Vue构造函数定义(实例文件)
core/instance/index.js
function Vue(options){
// 只能new不能直接执行
// ...
this._init(options)
}
// 给Vue的原型链上加点东西 Vue.prototype
/**
* 实例创建api(内部创建的时候使用)
* _init
*/
initMixin(Vue)
/**
* 数据相关的api
* $data
* $props
* $set
* $delete
* $watch
*/
stateMixin(Vue)
/**
* 事件监听相关的api
* $on
* $once
* $off
* $emit
*/
eventsMixin(Vue)
/**
* 在Vue原型链上增加属性
* _update
* $forceUpdate
* $destroy
*/
lifecycleMixin(Vue)
/**
* 执行 installRenderHelpers,挂载一些渲染相关的工具函数
* 渲染相关的api
* $nextTick
* _render
*/
renderMixin(Vue)
总结一下,在Vue类创建前已经有的属性
// -------静态属性和方法------------------
// 默认的options属性,和出入的参数合并
Vue.options = {
components: {
KeepAlive: {}
Transition: {}
TransitionGroup: {}
},
directives: {
model: {inserted: ƒ, componentUpdated: ƒ}
show: {bind: ƒ, update: ƒ, unbind: ƒ}
},
filters: {}
_base
}
Vue.verison
Vue.FunctionalRenderContext
Vue.config.mustUseProp
Vue.config.isReservedTag
Vue.config.isReservedAttr
Vue.config.getTagNamespace
Vue.config.isUnknownElement
Vue.use
Vue.mixin
Vue.extend
Vue.components
Vue.directive
Vue.filter
// -------实例属性和方法------------------
Vue.prototype.$isServer
Vue.prototype.$ssrContext
Vue.prototype.__patch__
Vue.prototype.$mount
// 数据相关
Vue.prototype.$data
Vue.prototype.props
Vue.prototype.$set
Vue.prototype.$delete
Vue.prototype.$watch
// 事件相关
Vue.prototype.$on
Vue.prototype.$once
Vue.prototype.$once
Vue.prototype.$emit
// 渲染相关
Vue.prototype._update
Vue.prototype.$forceUpdate
Vue.prototype.$destory
// 生命周期相关
// 挂载了一堆渲染工具函数
installRenderHelpers()
Vue.prototype.$nextTick
Vue.prototype._render
2.Vue实例的创建_init
// vue 真正的构造函数
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// 全局vue实例 🆔
vm._uid = uid++
// ...
// a flag to avoid this being observed
vm._isVue = true
// merge options
if (options && options._isComponent) {
initInternalComponent(vm, options)
} else {
// 自己开发的组件都会走到这一步,合并Vue之前已经生成好的options属性,再挂载到$options上
vm.$options = mergeOptions(
// 该函数会沿着继承链往上找到有options属性的地方
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
// 开发环境下做了render函数时候的代理,优化性能应该是,生产环境的时候就是他自己
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)
initProvide(vm) // resolve provide after data/props
// 执行实例创建完钩子
callHook(vm, 'created')
//...
// 挂载到真实的Dom
// 但是有的时候一般用链式调用 new Vue({}).$mount("#app")
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
接下来可能为陆续阅读实例初始化时候各个属性的具体操作,望大佬多多指正,未完待续。。。