跳到主要内容

官方实现

2023年06月11日
柏拉文
越努力,越幸运

一、src/core/instance/index.ts


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'
import type { GlobalAPI } from 'types/global-api'

function Vue(options) {
if (__DEV__ && !(this instanceof Vue)) {
warn('Vue is a constructor and should be called with the `new` keyword')
}

// 调用 Vue.prototype._init 方法,该方法是在 initMixin 中定义的
this._init(options)
}

// 定义 Vue.prototype._init 方法
initMixin(Vue)
/**
* 定义:
* Vue.prototype.$data
* Vue.prototype.$props
* Vue.prototype.$set
* Vue.prototype.$delete
* Vue.prototype.$watch
*/
stateMixin(Vue)
/**
* 定义 事件相关的 方法:
* Vue.prototype.$on
* Vue.prototype.$once
* Vue.prototype.$off
* Vue.prototype.$emit
*/
eventsMixin(Vue)
/**
* 定义:
* Vue.prototype._update
* Vue.prototype.$forceUpdate
* Vue.prototype.$destroy
*/
lifecycleMixin(Vue)
/**
* 执行 installRenderHelpers,在 Vue.prototype 对象上安装运行时便利程序
*
* 定义:
* Vue.prototype.$nextTick
* Vue.prototype._render
*/
renderMixin(Vue)

export default Vue as unknown as GlobalAPI

二、src/core/instance/state.ts stateMixin()


export function stateMixin(Vue: typeof Component) {
// data
const dataDef: any = {}
dataDef.get = function () {
return this._data
}
// props
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)
}
}
// 将 data 属性和 props 属性挂载到 Vue.prototype 对象上
// 这样在程序中就可以通过 this.$data 和 this.$props 来访问 data 和 props 对象了
Object.defineProperty(Vue.prototype, '$data', dataDef)
Object.defineProperty(Vue.prototype, '$props', propsDef)

Vue.prototype.$set = set
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()
}
}
}