携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第20天,点击查看活动详情
我们查看一下Vue实例化的源码文件:
// 源码文件 src\core\instance\index.ts
function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}
this._init(options)
}
//@ts-expect-error Vue has function type
initMixin(Vue)
//@ts-expect-error Vue has function type
stateMixin(Vue)
//@ts-expect-error Vue has function type
eventsMixin(Vue)
//@ts-expect-error Vue has function type
lifecycleMixin(Vue)
//@ts-expect-error Vue has function type
renderMixin(Vue)
export default Vue as unknown as GlobalAPI
可以看到实例化过程中就是执行了_init方法,这个方法在initMixin中声明在了Vue的原型对象上,而其它的几个方法类似,都是将给Vue的原型对象上声明了各种各样的方法并进行初始化:
- initMixin声明了实例的初始化方法(这篇不展开讲,后面单独说)
- stateMixin声明了响应性对象的相关方法
- eventsMixin声明了事件处理的相关方法
- lifecycleMixin声明了生命周期的相关方法
- renderMixin声明了渲染相关方法
stateMixin
stateMixin中主要是对响应性对象data,props的相关方法进行了处理,首先将二者分别挂载在$data,$props上:
// 源码文件:src\core\instance\state.ts
const dataDef: any = {}
dataDef.get = function () {
return this._data
}
const propsDef: any = {}
propsDef.get = function () {
return this._props
}
if (__DEV__) {
dataDef.set = function () {
warn(
'Avoid replacing instance root $data. ' +
'Use nested data properties instead.',
this
)
}
propsDef.set = function () {
warn(`$props is readonly.`, this)
}
}
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
声明$set,$props,$watch方法:
// 源码文件:src\core\instance\state.ts
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)
Vue.prototype.$set = set // set 和 del方法在observer/index中,具体原理后面API部分再讲
Vue.prototype.$delete = del
Vue.prototype.$watch = function (
expOrFn: string | (() => any),
cb: any,
options?: Record<string, any>
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
return function unwatchFn() {
watcher.teardown()
}
}
eventsMixin
eventsMixin中声明了事件相关的方法$on,$once,$off,$emit(具体原理和用法在后面实例方法篇单独说,篇幅有限这里就不贴全部代码了):
// 源码文件:src\core\instance\events.ts
export function eventsMixin(Vue: typeof Component) {
Vue.prototype.$on = function (
event: string | Array<string>,
fn: Function
): Component {
// ...
}
Vue.prototype.$once = function (event: string, fn: Function): Component {
// ...
}
Vue.prototype.$off = function (
event?: string | Array<string>,
fn?: Function
): Component {
// ...
}
Vue.prototype.$emit = function (event: string): Component {
// ...
}
}
lifecycleMixin
lifecycleMixin中声明了生命周期的相关方法_update,$forceUpdate,$destroy:
// 源码文件:src\core\instance\lifecycle.ts
export function lifecycleMixin(Vue: typeof Component) {
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
Vue.prototype.$forceUpdate = function () {}
Vue.prototype.$destroy = function () {}
}
renderMixin
renderMixin中声明了模板渲染的相关方法$nextTick和_render,并且挂载了渲染工具函数installRenderHelpers,提供了运行时Vue(手写render)的支持:
// 源码文件:src\core\instance\render.ts
export function lifecycleMixin(Vue: typeof Component) {
// install runtime convenience helpers
installRenderHelpers(Vue.prototype)
Vue.prototype.$nextTick = function (fn: (...args: any[]) => any) {}
Vue.prototype._render = function (): VNode {}
}
Vue原型初始化完毕之后,就可以开始使用了,用new Vue()进行实例化开始初始化Vue对象,进入Vue的生命周期,下一篇文章将详细解读一下这个过程。